mhc 1.2.4 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +14 -0
- data/README.org +37 -0
- data/Rakefile +1 -1
- data/bin/mhc +199 -3
- data/emacs/Cask +1 -1
- data/emacs/mhc-db.el +42 -7
- data/emacs/mhc-summary.el +3 -1
- data/emacs/mhc-vars.el +1 -1
- data/emacs/mhc.el +30 -6
- data/lib/mhc/calendar.rb +20 -0
- data/lib/mhc/command/init.rb +4 -4
- data/lib/mhc/config.rb +6 -2
- data/lib/mhc/converter.rb +74 -3
- data/lib/mhc/datastore.rb +9 -5
- data/lib/mhc/etag.rb +1 -1
- data/lib/mhc/formatter/html.rb +32 -0
- data/lib/mhc/formatter.rb +3 -0
- data/lib/mhc/templates/full-calendar.html.erb +417 -0
- data/lib/mhc/version.rb +1 -1
- data/mhc.gemspec +2 -1
- data/samples/japanese-holidays.mhcc +6 -6
- metadata +22 -5
data/lib/mhc/converter.rb
CHANGED
@@ -131,15 +131,86 @@ module Mhc
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
+
# https://github.com/rubyredrick/ri_cal
|
135
|
+
def value_part(unit, diff) # :nodoc:
|
136
|
+
(diff == 0) ? nil : "#{diff}#{unit}"
|
137
|
+
end
|
138
|
+
|
139
|
+
# https://github.com/rubyredrick/ri_cal
|
140
|
+
def from_datetimes(start, finish, sign = '') # :nodoc:
|
141
|
+
if start > finish
|
142
|
+
from_datetimes(finish, start, '-')
|
143
|
+
else
|
144
|
+
diff = finish - start
|
145
|
+
days_diff = diff.to_i
|
146
|
+
hours = (diff - days_diff) * 24
|
147
|
+
hour_diff = hours.to_i
|
148
|
+
minutes = (hours - hour_diff) * 60
|
149
|
+
min_diff = minutes.to_i
|
150
|
+
seconds = (minutes - min_diff) * 60
|
151
|
+
sec_diff = seconds.to_i
|
152
|
+
|
153
|
+
day_part = value_part('D',days_diff)
|
154
|
+
hour_part = value_part('H', hour_diff)
|
155
|
+
min_part = value_part('M', min_diff)
|
156
|
+
sec_part = value_part('S', sec_diff)
|
157
|
+
t_part = (hour_diff.abs + min_diff.abs + sec_diff.abs) == 0 ? "" : "T"
|
158
|
+
"P#{day_part}#{t_part}#{hour_part}#{min_part}#{sec_part}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Convert ~X-SC-Days:~ to RFC5545 3.8.2 ~RDATE~
|
163
|
+
#
|
164
|
+
# RDATE allows three types of format: PERIOD, DATE, DATE-TIME.
|
165
|
+
# + DATE :: 20140301
|
166
|
+
# + DATE-TIME :: 20140301T123000
|
167
|
+
# + PERIOD :: 20140301T123000/20140301T143000 or 20140301T123000/PT2H
|
168
|
+
#
|
169
|
+
# NOTE: *Google calenadr does not accept PERIOD*
|
170
|
+
# That's why we cannot make X-SC-Day: have different duration-period for each occurrence.
|
171
|
+
#
|
134
172
|
def rdates(event)
|
135
173
|
return nil if event.dates.empty?
|
136
|
-
|
174
|
+
# Get all RDATE candidates from X-SC-Date
|
175
|
+
ocs = Mhc::OccurrenceEnumerator.new(event, event.dates, empty_dates, empty_condition, empty_duration).map do |oc|
|
176
|
+
if oc.dtstart.respond_to?(:hour)
|
177
|
+
# duration = from_datetimes(oc.dtstart, oc.dtend)
|
178
|
+
|
179
|
+
# 20140301T123000/20140301T143000
|
180
|
+
dtstart = IcalendarImporter.tz_convert(oc.dtstart, dst_tzid: 'UTC').strftime("%Y%m%dT%H%M00Z")
|
181
|
+
dtend = IcalendarImporter.tz_convert(oc.dtend, dst_tzid: 'UTC').strftime("%Y%m%dT%H%M00Z")
|
182
|
+
|
183
|
+
dtstart + "/" + dtend
|
184
|
+
# dtstart + "/" + duration
|
185
|
+
else
|
186
|
+
oc.dtstart
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Check if all in X-SC-Date should be converted into RDATE,
|
191
|
+
# because the first occurrence of X-SC-Date might be dedicated
|
192
|
+
# to DTSTART in some particular case.
|
193
|
+
#
|
137
194
|
if event.recurring?
|
195
|
+
# Use all values of X-SC-Date as RDATE, because DTSTART
|
196
|
+
# should be calculated from recurrence-rule (X-SC-Cond and
|
197
|
+
# X-SC-Duration).
|
138
198
|
ocs
|
139
199
|
else
|
140
|
-
|
141
|
-
|
200
|
+
# This is Workaround for avoiding the serious bug in Android.
|
201
|
+
# Android badly ignores DTSTART-DTEND if RDATE is set.
|
202
|
+
# As a result, the first occurence is vanished.
|
203
|
+
# So, I set the first occurence twice; in RDATE and DTSTART.
|
204
|
+
return nil if ocs[1..-1].empty?
|
142
205
|
return ocs
|
206
|
+
|
207
|
+
# This is what I wanted to do:
|
208
|
+
# Remove the first occurence of X-SC-Date, because the first
|
209
|
+
# value should be dedicated to DTSTART.
|
210
|
+
#
|
211
|
+
# ocs = ocs[1..-1]
|
212
|
+
# return nil if ocs.empty?
|
213
|
+
# return ocs
|
143
214
|
end
|
144
215
|
end
|
145
216
|
|
data/lib/mhc/datastore.rb
CHANGED
@@ -25,7 +25,7 @@ module Mhc
|
|
25
25
|
Dir.foreach(".") do |ent|
|
26
26
|
parse_mhcc(ent).each {|ev|
|
27
27
|
next if category && !ev.in_category?(category)
|
28
|
-
next if recurrence && !ev.
|
28
|
+
next if recurrence && !(ev.recurrence_tag.to_s == recurrence)
|
29
29
|
yielder << ev
|
30
30
|
} if /\.mhcc$/ =~ ent
|
31
31
|
next unless /\.mhc$/ =~ ent
|
@@ -52,22 +52,25 @@ module Mhc
|
|
52
52
|
return Event.parse_file(path)
|
53
53
|
end
|
54
54
|
|
55
|
-
def create(event)
|
55
|
+
def create(event, draft = false)
|
56
56
|
if find_by_uid(event.uid)
|
57
57
|
raise "Already exist uid:#{uid} in #{@basedir}"
|
58
58
|
end
|
59
|
+
path = uid_to_path(event.uid, draft)
|
59
60
|
File.open(path, "w") do |f|
|
60
61
|
f.write(event.dump)
|
61
62
|
end
|
63
|
+
return path.to_s
|
62
64
|
end
|
63
65
|
|
64
|
-
def update(event)
|
65
|
-
unless path = uid_to_path(event.uid)
|
66
|
+
def update(event, draft = false)
|
67
|
+
unless path = uid_to_path(event.uid, draft)
|
66
68
|
raise "Not found uid:#{uid} in #{@basedir}"
|
67
69
|
end
|
68
70
|
File.open(path, "w") do |f|
|
69
71
|
f.write(event.dump)
|
70
72
|
end
|
73
|
+
return path.to_s
|
71
74
|
end
|
72
75
|
|
73
76
|
def delete(uid_or_event)
|
@@ -105,7 +108,8 @@ module Mhc
|
|
105
108
|
return Dir.glob(glob).first
|
106
109
|
end
|
107
110
|
|
108
|
-
def uid_to_path(uid)
|
111
|
+
def uid_to_path(uid, draft = false)
|
112
|
+
return @basedir + ('draft/' + uid + '.mhc') if draft
|
109
113
|
return @basedir + ('spool/' + uid + '.mhc')
|
110
114
|
end
|
111
115
|
|
data/lib/mhc/etag.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mhc
|
2
|
+
class Formatter
|
3
|
+
class Html < Base
|
4
|
+
TEMPLATE_DIR = File.expand_path("../../templates", __FILE__)
|
5
|
+
|
6
|
+
def initialize(date_range:, options:)
|
7
|
+
super(date_range: date_range, options: options)
|
8
|
+
@json_formatter = Json.new(date_range: date_range, options: options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(occurrence)
|
12
|
+
@json_formatter << occurrence
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def format_header(context)
|
18
|
+
require "erb"
|
19
|
+
template_path = File.expand_path("full-calendar.html.erb", TEMPLATE_DIR)
|
20
|
+
@template = ERB.new(File.open(template_path).read, nil, "-")
|
21
|
+
return ""
|
22
|
+
end
|
23
|
+
|
24
|
+
def format_body(context)
|
25
|
+
env = Struct.new(:json_event_array, :tzid)
|
26
|
+
mhc = env.new(@json_formatter.to_s, Mhc.default_tzid) # used in ERB template
|
27
|
+
@template.result(binding)
|
28
|
+
end
|
29
|
+
|
30
|
+
end # class Html
|
31
|
+
end # class Formatter
|
32
|
+
end # module Mhc
|
data/lib/mhc/formatter.rb
CHANGED
@@ -21,6 +21,8 @@ module Mhc
|
|
21
21
|
Howm.new(date_range: date_range, options:options)
|
22
22
|
when :json
|
23
23
|
Json.new(date_range: date_range, options:options)
|
24
|
+
when :html
|
25
|
+
Html.new(date_range: date_range, options:options)
|
24
26
|
else
|
25
27
|
raise Formatter::NameError.new("Unknown format: #{formatter} (#{formatter.class})")
|
26
28
|
end
|
@@ -37,6 +39,7 @@ module Mhc
|
|
37
39
|
autoload :OrgTable, "#{dir}/org_table.rb"
|
38
40
|
autoload :SymbolicExpression, "#{dir}/symbolic_expression.rb"
|
39
41
|
autoload :Text, "#{dir}/text.rb"
|
42
|
+
autoload :Html, "#{dir}/html.rb"
|
40
43
|
|
41
44
|
end # class Formatter
|
42
45
|
end # module Mhc
|
@@ -0,0 +1,417 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
|
8
|
+
<title>Calendar</title>
|
9
|
+
|
10
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.min.css" />
|
11
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
|
12
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css" />
|
13
|
+
|
14
|
+
<style media="screen" type="text/css">
|
15
|
+
.container {
|
16
|
+
// max-width: 100%;
|
17
|
+
width: auto;
|
18
|
+
}
|
19
|
+
|
20
|
+
.ui-draggable {
|
21
|
+
cursor: grab;
|
22
|
+
}
|
23
|
+
|
24
|
+
a {
|
25
|
+
cursor: pointer;
|
26
|
+
}
|
27
|
+
|
28
|
+
.fc-sun {
|
29
|
+
color:#gray;
|
30
|
+
background-color: #fff0f0;
|
31
|
+
}
|
32
|
+
|
33
|
+
.fc-sat {
|
34
|
+
color:#gray;
|
35
|
+
background-color: #f0f0ff;
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
#calendar .mhc-allday {
|
41
|
+
background-color: lightblue;
|
42
|
+
border-color: lightblue;
|
43
|
+
color: black;
|
44
|
+
}
|
45
|
+
|
46
|
+
#calendar .mhc-time-range {
|
47
|
+
background-color: #f7f7ff;
|
48
|
+
border-color: #f7f7ff;
|
49
|
+
color: black;
|
50
|
+
}
|
51
|
+
|
52
|
+
#calendar .mhc-time-range:hover {
|
53
|
+
background-color: aliceblue;
|
54
|
+
border-color: lavender;
|
55
|
+
color: black;
|
56
|
+
}
|
57
|
+
|
58
|
+
#calendar .mhc-category-holiday {
|
59
|
+
background-color: orangered;
|
60
|
+
border-color: orangered;
|
61
|
+
color: white;
|
62
|
+
}
|
63
|
+
|
64
|
+
#calendar .mhc-category-birthday {
|
65
|
+
background-color: #ffffe8;
|
66
|
+
border-color: #ffffe8;
|
67
|
+
color: black;
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
#side-calendar .mhc-category-birthday {
|
74
|
+
display: none;
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
#stuck-events .fc-list-heading {
|
81
|
+
display: none;
|
82
|
+
}
|
83
|
+
|
84
|
+
</style>
|
85
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
|
86
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
|
87
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.js"></script>
|
88
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.js"></script>
|
89
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.js"></script>
|
90
|
+
|
91
|
+
</head>
|
92
|
+
<body>
|
93
|
+
<!--
|
94
|
+
<div class="navmenu navmenu-default navmenu-fixed-left offcanvas">
|
95
|
+
<a class="navmenu-brand" href="#">brand</a>
|
96
|
+
<ul class="nav navmenu-nav">
|
97
|
+
<li><a href="#">Menu text 1</a></li>
|
98
|
+
<li><a href="#">Menu text 2</a></li>
|
99
|
+
<li><a href="#">Menu text 3</a></li>
|
100
|
+
</ul>
|
101
|
+
</div>
|
102
|
+
<div class="navbar navbar-default navbar-fixed-top">
|
103
|
+
<button type="button" class="navbar-toggle" data-toggle="offcanvas" data-target=".navmenu" data-canvas="body">
|
104
|
+
<span class="icon-bar"></span>
|
105
|
+
<span class="icon-bar"></span>
|
106
|
+
<span class="icon-bar"></span>
|
107
|
+
</button>
|
108
|
+
</div>
|
109
|
+
-->
|
110
|
+
|
111
|
+
<div class="container">
|
112
|
+
<div class="row">
|
113
|
+
|
114
|
+
<div class="col-xs-3">
|
115
|
+
<ul class="nav nav-tabs">
|
116
|
+
<li class="active"><a data-toggle="tab" href="#side-calendar">Past Events</a></li>
|
117
|
+
<li><a data-toggle="tab" href="#stuck-events">Stuck Events</a></li>
|
118
|
+
</ul>
|
119
|
+
<div class="tab-content">
|
120
|
+
<div id="side-calendar" class="tab-pane fade in active"></div>
|
121
|
+
<div id="stuck-events" class="tab-pane fade"></div>
|
122
|
+
</div>
|
123
|
+
</div><!-- col-xs-3 -->
|
124
|
+
|
125
|
+
<div class="col-xs-9" id="calendar"></div> <!-- col-xs-9 -->
|
126
|
+
</div><!-- row -->
|
127
|
+
</div><!-- /.container -->
|
128
|
+
|
129
|
+
<script>
|
130
|
+
function create_uuid() {
|
131
|
+
var d = +new Date();
|
132
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
133
|
+
.replace(/[xy]/g, function(c) {
|
134
|
+
var r = (d + Math.random() * 16) % 16 | 0;
|
135
|
+
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16).toUpperCase();
|
136
|
+
});
|
137
|
+
}
|
138
|
+
|
139
|
+
function max_height_for(element) {
|
140
|
+
var top = $(element).position().top;
|
141
|
+
return $(window).height() - top - 7;
|
142
|
+
}
|
143
|
+
|
144
|
+
function adjust_height(element) {
|
145
|
+
var height = max_height_for(element);
|
146
|
+
$(element).fullCalendar('option', 'height', height);
|
147
|
+
}
|
148
|
+
|
149
|
+
var json_event_array = [<%= mhc.json_event_array %>];
|
150
|
+
|
151
|
+
$(document).ready(function() {
|
152
|
+
|
153
|
+
$('#side-calendar').fullCalendar({
|
154
|
+
defaultView: 'listMonth',
|
155
|
+
header: {
|
156
|
+
left: '',
|
157
|
+
center: 'title',
|
158
|
+
right: ''
|
159
|
+
},
|
160
|
+
height: max_height_for('#side-calendar'),
|
161
|
+
editable: true,
|
162
|
+
eventResourceEditable: true,
|
163
|
+
eventLimit: true,
|
164
|
+
selectable: true,
|
165
|
+
droppable: true,
|
166
|
+
timezone: '<%= mhc.tzid %>',
|
167
|
+
timeFormat: "HH:mm",
|
168
|
+
displayEventEnd: false,
|
169
|
+
allDayText: "",
|
170
|
+
month: 'HH:mm',
|
171
|
+
week: 'HH:mm',
|
172
|
+
day: 'HH:mm',
|
173
|
+
// eventSources: [<%= $stuck_recurrences_json %>],
|
174
|
+
eventSources: json_event_array,
|
175
|
+
XeventDragStart: function(calEvent, jsEvent, ui, view) {
|
176
|
+
alert('Drag Event: ' + calEvent.title);
|
177
|
+
alert('Event ID: ' + calEvent.id);
|
178
|
+
alert('Coordinates: ' + jsEvent.pageX + ',' + jsEvent.pageY);
|
179
|
+
alert('View: ' + view.name);
|
180
|
+
// change the border color just for fun
|
181
|
+
$(this).css('border-color', 'red');
|
182
|
+
},
|
183
|
+
viewRender: function(view, element) {
|
184
|
+
$('tr.fc-list-item').each(function() {
|
185
|
+
var duration;
|
186
|
+
var seg = $(this).data('fc-seg');
|
187
|
+
var myevent = seg.footprint.getEventLegacy();
|
188
|
+
if (myevent.end) {
|
189
|
+
var minutes = moment.duration(myevent.end.diff(myevent.start)).asMinutes();
|
190
|
+
var days = Math.floor(minutes/(24*60));
|
191
|
+
minutes -= days * 24 * 60;
|
192
|
+
var hours = Math.floor(minutes/60);
|
193
|
+
minutes -= hours * 60;
|
194
|
+
duration = days + "." + hours + ":" + minutes;
|
195
|
+
} else {
|
196
|
+
duration = "0.00:00";
|
197
|
+
}
|
198
|
+
if (myevent.title == "母の日") {
|
199
|
+
// alert('My Event: ' + myevent.title);
|
200
|
+
// alert('Duration: ' + duration);
|
201
|
+
}
|
202
|
+
var uuid = create_uuid();
|
203
|
+
// alert('Seg: ' + seg);
|
204
|
+
$(this).data('event', {
|
205
|
+
title: myevent.title,
|
206
|
+
allDay: myevent.allDay,
|
207
|
+
start: myevent.start.format("HH:mm"),
|
208
|
+
duration: duration,
|
209
|
+
stick: true,
|
210
|
+
className: myevent.className
|
211
|
+
});
|
212
|
+
});
|
213
|
+
|
214
|
+
$('tr.fc-list-item').draggable({
|
215
|
+
appendTo: "#calendar",
|
216
|
+
cursorAt: {top: 5, left: 5},
|
217
|
+
iframeFix: true,
|
218
|
+
refreshPositions: true,
|
219
|
+
scroll: false,
|
220
|
+
cursor: "move",
|
221
|
+
revert: true, // will cause the event to go back to its
|
222
|
+
revertDuration: 0, // original position after the drag
|
223
|
+
helper: "clone",
|
224
|
+
zIndex: 100,
|
225
|
+
opacity: 0.35,
|
226
|
+
|
227
|
+
start: function(event, ui) {
|
228
|
+
}
|
229
|
+
});
|
230
|
+
if(view.name == 'listMonth') {
|
231
|
+
adjust_height('#side-calendar');
|
232
|
+
}
|
233
|
+
},
|
234
|
+
windowResize: function(view) {
|
235
|
+
if(view.name == 'listMonth') {
|
236
|
+
adjust_height('#side-calendar');
|
237
|
+
}
|
238
|
+
}
|
239
|
+
});
|
240
|
+
|
241
|
+
$('#stuck-events').fullCalendar({
|
242
|
+
defaultView: 'listall',
|
243
|
+
Xheader: {
|
244
|
+
left: '',
|
245
|
+
center: '',
|
246
|
+
right: ''
|
247
|
+
},
|
248
|
+
header: false,
|
249
|
+
views: {
|
250
|
+
listall: {
|
251
|
+
type: 'list',
|
252
|
+
duration: { days: 3650},
|
253
|
+
dayCount: 30
|
254
|
+
}
|
255
|
+
},
|
256
|
+
height: max_height_for('#side-calendar'), // XXX
|
257
|
+
editable: true,
|
258
|
+
eventResourceEditable: true,
|
259
|
+
eventLimit: true,
|
260
|
+
selectable: true,
|
261
|
+
droppable: true,
|
262
|
+
timezone: '<%= mhc.tzid %>',
|
263
|
+
timeFormat: " ",
|
264
|
+
allDayText: "",
|
265
|
+
month: 'HH:mm',
|
266
|
+
week: 'HH:mm',
|
267
|
+
day: 'HH:mm',
|
268
|
+
eventSources: [<%= $stuck_recurrences_json %>],
|
269
|
+
XeventDragStart: function(calEvent, jsEvent, ui, view) {
|
270
|
+
alert('Drag Event: ' + calEvent.title);
|
271
|
+
alert('Event ID: ' + calEvent.id);
|
272
|
+
alert('Coordinates: ' + jsEvent.pageX + ',' + jsEvent.pageY);
|
273
|
+
alert('View: ' + view.name);
|
274
|
+
// change the border color just for fun
|
275
|
+
$(this).css('border-color', 'red');
|
276
|
+
},
|
277
|
+
viewRender: function(view, element) {
|
278
|
+
$('tr.fc-list-item').each(function() {
|
279
|
+
var duration;
|
280
|
+
var seg = $(this).data('fc-seg');
|
281
|
+
var myevent = seg.footprint.getEventLegacy();
|
282
|
+
if (myevent.end) {
|
283
|
+
var minutes = moment.duration(myevent.end.diff(myevent.start)).asMinutes();
|
284
|
+
var days = Math.floor(minutes/(24*60));
|
285
|
+
minutes -= days * 24 * 60;
|
286
|
+
var hours = Math.floor(minutes/60);
|
287
|
+
minutes -= hours * 60;
|
288
|
+
duration = days + "." + hours + ":" + minutes;
|
289
|
+
} else {
|
290
|
+
duration = "0.00:00";
|
291
|
+
}
|
292
|
+
if (myevent.title == "母の日") {
|
293
|
+
// alert('My Event: ' + myevent.title);
|
294
|
+
// alert('Duration: ' + duration);
|
295
|
+
}
|
296
|
+
var uuid = create_uuid();
|
297
|
+
// alert('Seg: ' + seg);
|
298
|
+
$(this).data('event', {
|
299
|
+
title: myevent.title,
|
300
|
+
allDay: myevent.allDay,
|
301
|
+
start: myevent.start.format("HH:mm"),
|
302
|
+
duration: duration,
|
303
|
+
stick: true,
|
304
|
+
className: myevent.className
|
305
|
+
});
|
306
|
+
});
|
307
|
+
|
308
|
+
$('tr.fc-list-item').draggable({
|
309
|
+
appendTo: "#calendar",
|
310
|
+
cursorAt: {top: 5, left: 5},
|
311
|
+
iframeFix: true,
|
312
|
+
refreshPositions: true,
|
313
|
+
scroll: false,
|
314
|
+
cursor: "move",
|
315
|
+
revert: true, // will cause the event to go back to its
|
316
|
+
revertDuration: 0, // original position after the drag
|
317
|
+
helper: "clone",
|
318
|
+
zIndex: 100,
|
319
|
+
opacity: 0.35,
|
320
|
+
|
321
|
+
start: function(event, ui) {
|
322
|
+
}
|
323
|
+
});
|
324
|
+
if(view.name == 'listMonth') {
|
325
|
+
adjust_height('#stuck-events');
|
326
|
+
}
|
327
|
+
},
|
328
|
+
windowResize: function(view) {
|
329
|
+
if(view.name == 'listMonth') {
|
330
|
+
adjust_height('#stuck-events');
|
331
|
+
}
|
332
|
+
}
|
333
|
+
});
|
334
|
+
|
335
|
+
$('#calendar').fullCalendar({
|
336
|
+
header: {
|
337
|
+
left: 'prev,next today',
|
338
|
+
center: 'title',
|
339
|
+
right: 'month,agendaWeek,agendaDay,listMonth'
|
340
|
+
},
|
341
|
+
firstDay: 1,
|
342
|
+
height: max_height_for('#calendar'),
|
343
|
+
editable: true,
|
344
|
+
eventResourceEditable: true,
|
345
|
+
eventLimit: true,
|
346
|
+
selectable: true,
|
347
|
+
droppable: true,
|
348
|
+
|
349
|
+
// drop: Event ではない draggable からドロップされたとき.
|
350
|
+
// draggable が event として認識できないようなときでも発火する
|
351
|
+
drop: function(date) {
|
352
|
+
// alert("Dropped on " + date.format());
|
353
|
+
},
|
354
|
+
|
355
|
+
// eventReceive: Event ではない draggable からドロップされたとき
|
356
|
+
// draggable が event として認識可能な property を持っている場合だけ発火する
|
357
|
+
eventReceive: function(event) {
|
358
|
+
event.id = create_uuid(); // XXX! これがうまくいかない
|
359
|
+
$('#calendar').fullCalendar('updateEvent', event);
|
360
|
+
// alert("Drop event from ourter world! ID: " + event.id);
|
361
|
+
},
|
362
|
+
|
363
|
+
// eventDrop: 既に登録されている event を変更したとき
|
364
|
+
eventDrop: function(event, delta, revertFunc, jsEvent, ui, view) {
|
365
|
+
// alert("eventDrop:" + event.title);
|
366
|
+
// alert("eventDrop:" + event.id);
|
367
|
+
},
|
368
|
+
|
369
|
+
// return (this.eventInstance || this.eventDef).toLegacy()
|
370
|
+
eventClick: function(calEvent, jsEvent, view) {
|
371
|
+
var yesno = prompt('Do you delete ' + calEvent.title + '?');
|
372
|
+
// alert('Event ID: ' + calEvent.id);
|
373
|
+
if (yesno == "yes"){
|
374
|
+
$('#calendar').fullCalendar('removeEvents', [calEvent.id]);
|
375
|
+
}
|
376
|
+
// alert('This Event: ' + $(this).getEventLegacy().title);
|
377
|
+
//alert('Coordinates: ' + jsEvent.pageX + ',' + jsEvent.pageY);
|
378
|
+
//alert('View: ' + view.name);
|
379
|
+
// change the border color just for fun
|
380
|
+
// $(this).css('border-color', 'red');
|
381
|
+
},
|
382
|
+
|
383
|
+
timezone: '<%= mhc.tzid %>',
|
384
|
+
timeFormat: "HH:mm",
|
385
|
+
allDayText: "",
|
386
|
+
month: 'HH:mm',
|
387
|
+
week: 'HH:mm',
|
388
|
+
day: 'HH:mm',
|
389
|
+
eventSources: json_event_array,
|
390
|
+
// eventSources: [<%= mhc.json_event_array %>],
|
391
|
+
viewRender: function(view, element) {
|
392
|
+
if(view.name == 'month') {
|
393
|
+
adjust_height('#calendar');
|
394
|
+
adjust_height('#stuck-events');
|
395
|
+
}
|
396
|
+
var currentDate = $('#calendar').fullCalendar('getDate');
|
397
|
+
// alert("The current date of the calendar is " + currentDate.format());
|
398
|
+
$('#side-calendar').fullCalendar('gotoDate', currentDate.subtract(1, 'y'));
|
399
|
+
$('#stuck-events').fullCalendar('gotoDate', currentDate.subtract(5, 'y'));
|
400
|
+
},
|
401
|
+
windowResize: function(view) {
|
402
|
+
if(view.name == 'month') {
|
403
|
+
adjust_height('#calendar');
|
404
|
+
adjust_height('#stuck-events');
|
405
|
+
}
|
406
|
+
}
|
407
|
+
}) // $('#calendar')
|
408
|
+
|
409
|
+
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
410
|
+
var target = $(e.target).attr("href") // activated tab
|
411
|
+
adjust_height(target);
|
412
|
+
});
|
413
|
+
|
414
|
+
});
|
415
|
+
</script>
|
416
|
+
</body>
|
417
|
+
</html>
|
data/lib/mhc/version.rb
CHANGED
data/mhc.gemspec
CHANGED
@@ -23,7 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
-
spec.add_runtime_dependency "thor", ">=
|
26
|
+
spec.add_runtime_dependency "thor", ">= 1.2.0"
|
27
|
+
spec.add_runtime_dependency "rexml", ">= 3.2.4"
|
27
28
|
spec.add_runtime_dependency "ri_cal", ">= 0.8.8"
|
28
29
|
spec.add_runtime_dependency "tzinfo", ">= 1.2.2"
|
29
30
|
spec.add_runtime_dependency "tzinfo-data", ">= 1.2015.4"
|
@@ -31,14 +31,14 @@ X-SC-Record-Id: AC1B378C-BAFE-4B6E-AF9C-78C2377E8AA4
|
|
31
31
|
X-SC-Subject: 天皇誕生日
|
32
32
|
X-SC-Category: Holiday Japanese
|
33
33
|
X-SC-Cond: 29 Apr
|
34
|
-
X-SC-Duration:
|
34
|
+
X-SC-Duration: 19490429-19880429
|
35
35
|
X-SC-Record-Id: B78EAAEE-9963-4573-9EC7-0879F8940AEE
|
36
36
|
|
37
37
|
X-SC-Subject: みどりの日
|
38
38
|
X-SC-Category: Holiday Japanese
|
39
39
|
X-SC-Cond: 29 Apr
|
40
40
|
X-SC-Duration: 19890429-20060429
|
41
|
-
X-SC-Record-Id:
|
41
|
+
X-SC-Record-Id: 8C05BF80-006C-4FA7-8CF1-5F1C18CB8641
|
42
42
|
|
43
43
|
X-SC-Subject: 昭和の日
|
44
44
|
X-SC-Category: Holiday Japanese
|
@@ -186,12 +186,12 @@ X-SC-Day: 19730430 19730924 19740506 19740916 19741104 19751124
|
|
186
186
|
20180430 20180924 20181224 20190506 20190812 20191104 20200224 20200506
|
187
187
|
20210809
|
188
188
|
20230102 20240212 20240506 20240812 20240923 20241104 20250224 20250506
|
189
|
-
20251124 20260506 20270322 20290212 20290430 20290924
|
189
|
+
20251124 20260506 20270322 20290212 20290430 20290924
|
190
190
|
20300506 20300812 20301104 20310224 20310506 20311124 20330321 20340102
|
191
|
-
20350212 20350430 20350924
|
192
|
-
20400102 20400430
|
191
|
+
20350212 20350430 20350924 20360506 20361124 20370506
|
192
|
+
20400102 20400430 20410506 20410812 20411104 20420224 20420506
|
193
193
|
20421124 20430506 20440321 20450102 20460212 20460430 20460924
|
194
|
-
|
194
|
+
20470506 20470812 20471104 20480224 20480506 20500321
|
195
195
|
X-SC-Category: Holiday Japanese
|
196
196
|
X-SC-Record-Id: E2D696DF-EB49-44D7-B06C-812B10BD99A2
|
197
197
|
|