1
0

finish add/update event page

This commit is contained in:
2021-02-09 17:10:05 +08:00
parent d3d7731aff
commit ae470e2638
11 changed files with 347 additions and 90 deletions

View File

@@ -228,7 +228,7 @@ class CalendarDatabase(object):
# get prev data # get prev data
self.cursor.execute('SELECT * FROM calendar WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (uuid, lastChange)) self.cursor.execute('SELECT * FROM calendar WHERE [ccn_uuid] = ? AND [ccn_lastChange] = ?;', (uuid, lastChange))
analyseData = self.cursor.fetchone() analyseData = list(self.cursor.fetchone())
# construct update data # construct update data
lastupdate = utils.GenerateUUID() lastupdate = utils.GenerateUUID()

View File

@@ -28,7 +28,7 @@ def ResolveLoopStr(strl, starttime, tzoffset):
return int(cache.group(1)) # group 1 is datetime return int(cache.group(1)) # group 1 is datetime
cache = precompiledLoopStopRules['times'].search(loopStopRules) cache = precompiledLoopStopRules['times'].search(loopStopRules)
if cache is not None: if cache is not None:
loopTimes = cache # for follwing calc loopTimes = int(cache.group(1)) # for follwing calc
else: else:
raise Exception('Invalid loopStopRules') # invalid rules raise Exception('Invalid loopStopRules') # invalid rules
@@ -41,7 +41,7 @@ def ResolveLoopStr(strl, starttime, tzoffset):
def LoopHandle_Year(searchResult, starttime, times, tzoffset): def LoopHandle_Year(searchResult, starttime, times, tzoffset):
clientDate = datetime.datetime.fromtimestamp(starttime, UTCTimezone(tzoffset)) clientDate = datetime.datetime.fromtimestamp(starttime * 60, UTCTimezone(tzoffset))
isStrict = searchResult.group(1) == 'S' isStrict = searchResult.group(1) == 'S'
yearSpan = int(searchResult.group(2)) yearSpan = int(searchResult.group(2))
@@ -77,13 +77,14 @@ def LoopHandle_Month(searchResult, starttime, times, tzoffset):
# we should get original data in each method # we should get original data in each method
times -= 1 times -= 1
clientDate = datetime.datetime.fromtimestamp(starttime, UTCTimezone(tzoffset)) clientDate = datetime.datetime.fromtimestamp(starttime * 60, UTCTimezone(tzoffset))
newYear = clientYear = clientDate.year newYear = clientYear = clientDate.year
newMonth = clientMonth = clientDate.month newMonth = clientMonth = clientDate.month
newDay = clientDay = clientDate.day newDay = clientDay = clientDate.day
# data struct # data struct
# dayStatistics = # dayStatistics =
# (dayForwards, dayBackwards, weeksForward, dayOfWeekForward, weeksBackwards, dayOfWeekBackward) # (dayForwards || dayBackwards || weeksForward, dayOfWeek || weeksBackwards, dayOfWeek)
# ( A || B || C || D )
dayStatistics = GetDayInMonth(clientYear, clientMonth, clientDay) dayStatistics = GetDayInMonth(clientYear, clientMonth, clientDay)
if isStrict: if isStrict:
@@ -139,13 +140,16 @@ def LoopHandle_Week(searchResult, starttime, times, tzoffset):
raise Exception('Invalid week format') raise Exception('Invalid week format')
weekSpan = int(searchResult.group(2)) weekSpan = int(searchResult.group(2))
nowDayOfWeek = datetime.datetime.fromtimestamp(starttime, UTCTimezone(tzoffset)).weekday() nowDayOfWeek = datetime.datetime.fromtimestamp(starttime * 60, UTCTimezone(tzoffset)).weekday()
if not weekOccupied[nowDayOfWeek]: if not weekOccupied[nowDayOfWeek]:
times+=1 # if first event is not suit for week loop rules, add one more event to suit it. times-=1 # if first event is not suit for week loop rules, minus one more event to suit it.
fullWeek = times / weekEventCount fullWeek = int(times / weekEventCount)
remainEvent = times % weekEventCount remainEvent = times % weekEventCount
print(fullWeek)
print(remainEvent)
print(nowDayOfWeek)
val = DAY7_SPAN * fullWeek * weekSpan val = starttime + DAY7_SPAN * fullWeek * weekSpan
if val > MAX_TIMESTAMP: if val > MAX_TIMESTAMP:
return MAX_TIMESTAMP # return now, to reduce calc usage return MAX_TIMESTAMP # return now, to reduce calc usage
@@ -231,21 +235,15 @@ def DayOfWeek(year, month, day):
def GetDayInMonth(year, month, day): def GetDayInMonth(year, month, day):
days = MonthDayCount[month - 1] + (1 if (month == 2 and IsLeapYear(year)) else 0) days = MonthDayCount[month - 1] + (1 if (month == 2 and IsLeapYear(year)) else 0)
firstDayOfWeek = DayOfWeek(year, month, 1) firstDayOfWeek = DayOfWeek(year, month, 1)
lastDayOfWeek = (firstDayOfWeek + days - 1) % 7
dayOfWeek = (firstDayOfWeek + day - 1) % 7 dayOfWeek = (firstDayOfWeek + day - 1) % 7
dayForwards = day dayForwards = day
dayBackwards = days - day + 1 dayBackwards = days - day + 1
weeksForward = (dayForwards - 1) / 7 weeksForward = int((dayForwards - 1) / 7) + 1
weeksBackwards = (dayBackwards - 1) / 7 weeksBackwards = int((dayBackwards - 1) / 7) + 1
dayOfWeekForward = (firstDayOfWeek + ((dayForwards - 1) % 7)) % 7 return (dayForwards, dayBackwards, weeksForward, dayOfWeek, weeksBackwards, dayOfWeek)
# 7 don't change week
# # just keep this is the positive number and prevent pretential minus number calc problem
dayOfWeekBackward = (7 + lastDayOfWeek - ((dayBackwards - 1) % 7)) % 7
return (dayForwards, dayBackwards, weeksForward, dayOfWeekForward, weeksBackwards, dayOfWeekBackward)
def GetMonthWeekStatistics(year, month): def GetMonthWeekStatistics(year, month):
days = MonthDayCount[month - 1] + (1 if (month == 2 and IsLeapYear(year)) else 0) days = MonthDayCount[month - 1] + (1 if (month == 2 and IsLeapYear(year)) else 0)
@@ -253,7 +251,7 @@ def GetMonthWeekStatistics(year, month):
lastDayOfWeek = (firstDayOfWeek + days - 1) % 7 lastDayOfWeek = (firstDayOfWeek + days - 1) % 7
result = [4, 4, 4, 4, 4, 4, 4] result = [4, 4, 4, 4, 4, 4, 4]
remain = (days - 1) % 7 remain = days % 7
week = firstDayOfWeek week = firstDayOfWeek
while remain > 0: while remain > 0:
result[week % 7] += 1 result[week % 7] += 1
@@ -273,4 +271,4 @@ class UTCTimezone(datetime.tzinfo):
return 'UTC {}'.format(self._offset) return 'UTC {}'.format(self._offset)
def dst(self, dt): def dst(self, dt):
return timedelta(0) return datetime.timedelta(0)

View File

@@ -173,8 +173,7 @@ def api_calendar_addHandle():
('eventDateTimeStart', int, False), ('eventDateTimeStart', int, False),
('eventDateTimeEnd', int, False), ('eventDateTimeEnd', int, False),
('loopRules', str, False), ('loopRules', str, False),
('timezoneOffset', int, False), ('timezoneOffset', int, False)))
('lastChange', str, False)))
@app.route('/api/calendar/delete', methods=['POST']) @app.route('/api/calendar/delete', methods=['POST'])
def api_calendar_deleteHandle(): def api_calendar_deleteHandle():

View File

@@ -27,18 +27,18 @@ ccn-i18n-universal-week-4=Thursday
ccn-i18n-universal-week-5=Friday ccn-i18n-universal-week-5=Friday
ccn-i18n-universal-week-6=Saturday ccn-i18n-universal-week-6=Saturday
ccn-i18n-universal-week-7=Sunday ccn-i18n-universal-week-7=Sunday
ccn-i18n-universal-month-1=1月 ccn-i18n-universal-month-1=January
ccn-i18n-universal-month-2=2月 ccn-i18n-universal-month-2=February
ccn-i18n-universal-month-3=3月 ccn-i18n-universal-month-3=March
ccn-i18n-universal-month-4=4月 ccn-i18n-universal-month-4=April
ccn-i18n-universal-month-5=5月 ccn-i18n-universal-month-5=May
ccn-i18n-universal-month-6=6月 ccn-i18n-universal-month-6=June
ccn-i18n-universal-month-7=7月 ccn-i18n-universal-month-7=July
ccn-i18n-universal-month-8=8月 ccn-i18n-universal-month-8=August
ccn-i18n-universal-month-9=9月 ccn-i18n-universal-month-9=September
ccn-i18n-universal-month-10=10月 ccn-i18n-universal-month-10=October
ccn-i18n-universal-month-11=11月 ccn-i18n-universal-month-11=November
ccn-i18n-universal-month-12=12月 ccn-i18n-universal-month-12=December
ccn-i18n-messagebox-confirm=OK ccn-i18n-messagebox-confirm=OK
ccn-i18n-messagebox-title=Notification ccn-i18n-messagebox-title=Notification
@@ -50,6 +50,7 @@ ccn-i18n-js-fail-add=An add operation failed. It may caused by wrong arguments.
ccn-i18n-js-fail-update=An update operation failed. It may caused by wrong arguments or lost target. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data. ccn-i18n-js-fail-update=An update operation failed. It may caused by wrong arguments or lost target. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.
ccn-i18n-js-fail-delete=A delete operation failed. It may caused by no matched item. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data. ccn-i18n-js-fail-delete=A delete operation failed. It may caused by no matched item. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.
ccn-i18n-js-success=Operation OK. ccn-i18n-js-success=Operation OK.
ccn-i18n-js-fail-form=Your filled event form is not fufilled or have error. Please check it and try again.
ccn-i18n-home-desc=<h1 class="title">coconut-leaf</h1><p>A light, self-host calendar system.</p><p>Originally, this app is served for yyc12345 personal use.</p><br /><p>Pull request / issue / translation are welcomed.</p><p>Submit them in our <a href="https://github.com/yyc12345/coconut-leaf">GitHub project</a>.</p><p>This project source code is licensed <a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>.</p> ccn-i18n-home-desc=<h1 class="title">coconut-leaf</h1><p>A light, self-host calendar system.</p><p>Originally, this app is served for yyc12345 personal use.</p><br /><p>Pull request / issue / translation are welcomed.</p><p>Submit them in our <a href="https://github.com/yyc12345/coconut-leaf">GitHub project</a>.</p><p>This project source code is licensed <a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>.</p>
@@ -88,15 +89,15 @@ ccn-i18n-event-loopMonth-span=Month span
ccn-i18n-event-loopWeek-option=Month mode ccn-i18n-event-loopWeek-option=Month mode
ccn-i18n-event-loopWeek-optionA=Day {0} in month ccn-i18n-event-loopWeek-optionA=Day {0} in month
ccn-i18n-event-loopWeek-optionB=Day {0} from the end of the month ccn-i18n-event-loopWeek-optionB=Day {0} from the end of the month
ccn-i18n-event-loopWeek-optionC=Week {0}, day {1} in month ccn-i18n-event-loopWeek-optionC=Day {1} in week {0}
ccn-i18n-event-loopWeek-optionD=Week {0}, day {1} from the end of the month ccn-i18n-event-loopWeek-optionD=Day {1} in week {0} from the end of the month
ccn-i18n-event-loopYear-span=Year span ccn-i18n-event-loopYear-span=Year span
ccn-i18n-event-loopStop=Event Loop Stop ccn-i18n-event-loopStop=Event Loop Stop
ccn-i18n-event-loopStop-forever=Forever ccn-i18n-event-loopStop-forever=Forever
ccn-i18n-event-loopStop-datetime=Date Time ccn-i18n-event-loopStop-datetime=Date Time
ccn-i18n-event-loopStop-times=Times ccn-i18n-event-loopStop-times=Times
ccn-i18n-event-timezone-title=Timezone ccn-i18n-event-timezone-title=Timezone
ccn-i18n-event-timezone-warning=The timezone of this event is not corresponding with your current timezone. You can choose a timezone option in follwing content. If you are not familar with this, please pick keep timezone. ccn-i18n-event-timezone-warning=The timezone of this event is not corresponding with your current timezone. All of date and time in this page are shown as the original timezone of this event. You can choose a timezone option in follwing content. If you are not familar with this, please pick keep timezone.
ccn-i18n-event-timezone-keep=Keep timezone ccn-i18n-event-timezone-keep=Keep timezone
ccn-i18n-event-timezone-replace=Use my timezone ccn-i18n-event-timezone-replace=Use my timezone
ccn-i18n-event-strictMode-title=Strict Mode in Event Loop ccn-i18n-event-strictMode-title=Strict Mode in Event Loop

View File

@@ -50,6 +50,7 @@ ccn-i18n-js-fail-add=一个添加操作失败了,可能是您输入的参数
ccn-i18n-js-fail-update=一个更新操作失败了,可能是没有找到匹配的条目或者您的参数输入错误。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。 ccn-i18n-js-fail-update=一个更新操作失败了,可能是没有找到匹配的条目或者您的参数输入错误。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。
ccn-i18n-js-fail-delete=一个删除操作失败了,可能是没有找到对应条目。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。 ccn-i18n-js-fail-delete=一个删除操作失败了,可能是没有找到对应条目。刷新页面可能会解决问题。请在刷新页面前备份好自己的数据。
ccn-i18n-js-success=操作成功 ccn-i18n-js-success=操作成功
ccn-i18n-js-fail-form=您所填写的事件内容存在缺漏或有错误字段,请检查后再提交。
ccn-i18n-home-desc=<h1 class="title">coconut-leaf</h1><p>一个轻量的自建日历系统</p><p>原本是出于yyc12345的个人使用而制作的。</p><br /><p>欢迎提出Pull request / issue / 翻译</p><p>将他们提交到我们的<a href="https://github.com/yyc12345/coconut-leaf">GitHub项目</a>.</p><p>本工程代码使用<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>授权。</p> ccn-i18n-home-desc=<h1 class="title">coconut-leaf</h1><p>一个轻量的自建日历系统</p><p>原本是出于yyc12345的个人使用而制作的。</p><br /><p>欢迎提出Pull request / issue / 翻译</p><p>将他们提交到我们的<a href="https://github.com/yyc12345/coconut-leaf">GitHub项目</a>.</p><p>本工程代码使用<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL v3</a>授权。</p>
@@ -94,15 +95,15 @@ ccn-i18n-event-loopMonth-span=间隔月数
ccn-i18n-event-loopWeek-option=月份模式 ccn-i18n-event-loopWeek-option=月份模式
ccn-i18n-event-loopWeek-optionA=第{0}天 ccn-i18n-event-loopWeek-optionA=第{0}天
ccn-i18n-event-loopWeek-optionB=倒数第{0}天 ccn-i18n-event-loopWeek-optionB=倒数第{0}天
ccn-i18n-event-loopWeek-optionC=第{0}个星期{1} ccn-i18n-event-loopWeek-optionC=第{0}个星期{1}
ccn-i18n-event-loopWeek-optionD=倒数第{0}个星期{1} ccn-i18n-event-loopWeek-optionD=倒数第{0}个星期{1}
ccn-i18n-event-loopYear-span=间隔年数 ccn-i18n-event-loopYear-span=间隔年数
ccn-i18n-event-loopStop=事件循环停止方式 ccn-i18n-event-loopStop=事件循环停止方式
ccn-i18n-event-loopStop-forever=永不停止 ccn-i18n-event-loopStop-forever=永不停止
ccn-i18n-event-loopStop-datetime=指定时间 ccn-i18n-event-loopStop-datetime=指定时间
ccn-i18n-event-loopStop-times=指定次数 ccn-i18n-event-loopStop-times=指定次数
ccn-i18n-event-timezone-title=时区设定 ccn-i18n-event-timezone-title=时区设定
ccn-i18n-event-timezone-warning=您当前设置的事件的时区与您的时区不匹配,您可以在下面修改您对于此事件的时区选择,如果您不熟悉时区,请选择保持原有时区。 ccn-i18n-event-timezone-warning=您当前设置的事件的时区与您的时区不匹配,本页面以事件的原时区进行时间显示。您可以在下面修改您对于此事件的时区选择,如果您不熟悉时区,请选择保持原有时区。
ccn-i18n-event-timezone-keep=保持原有时区 ccn-i18n-event-timezone-keep=保持原有时区
ccn-i18n-event-timezone-replace=使用我现在的时区 ccn-i18n-event-timezone-replace=使用我现在的时区
ccn-i18n-event-strictMode-title=循环的严格与宽松 ccn-i18n-event-strictMode-title=循环的严格与宽松

View File

@@ -200,20 +200,28 @@ function ccn_api_calendar_getDetail(_uuid) {
} }
function ccn_api_calendar_update(_uuid, _belongTo, _title, _description, _eventDateTimeStart, _eventDateTimeEnd, _loopRules, _timezoneOffset, _lastChange) { function ccn_api_calendar_update(_uuid, _belongTo, _title, _description, _eventDateTimeStart, _eventDateTimeEnd, _loopRules, _timezoneOffset, _lastChange) {
var data = {};
if (typeof(_belongTo) != 'undefined')
data.belongTo = _belongTo;
if (typeof(_title) != 'undefined')
data.title = _title;
if (typeof(_description) != 'undefined')
data.description = _description;
if (typeof(_eventDateTimeStart) != 'undefined')
data.eventDateTimeStart = _eventDateTimeStart;
if (typeof(_eventDateTimeEnd) != 'undefined')
data.eventDateTimeEnd = _eventDateTimeEnd;
if (typeof(_loopRules) != 'undefined')
data.loopRules = _loopRules;
if (typeof(_timezoneOffset) != 'undefined')
data.timezoneOffset = _timezoneOffset;
data.token = GetApiToken();
data.uuid = _uuid;
data.lastChange = _lastChange;
return ccn_api_dataTemplate( return ccn_api_dataTemplate(
'/api/calendar/update', '/api/calendar/update',
{ data
token: GetApiToken(),
uuid: _uuid,
belongTo: _belongTo,
title: _title,
description: _description,
eventDateTimeStart: _eventDateTimeStart,
eventDateTimeEnd: _eventDateTimeEnd,
loopRules: _loopRules,
timezoneOffset: _timezoneOffset,
lastChange: _lastChange
}
); );
} }

View File

@@ -1,3 +1,4 @@
// NOTE: this file is sync with dt.py. if this file or dt.py have bugs, all code should be changed
ccn_datetime_monthDayCount = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; ccn_datetime_monthDayCount = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
ccn_datetime_MIN_YEAR = 1950; ccn_datetime_MIN_YEAR = 1950;
@@ -47,15 +48,16 @@ function ccn_datetime_ResolveLoopRules4UI(strl) {
var loopStopRules = undefined; var loopStopRules = undefined;
if (ccn_datetime_precompiledLoopRules.year.test(sp[0])) { if (ccn_datetime_precompiledLoopRules.year.test(sp[0])) {
loopRules = [1, RegExp.$1 == 'S', parseInt(RegExp.$2)]; loopRules = [0, RegExp.$1 == 'S', parseInt(RegExp.$2)];
} else if (ccn_datetime_precompiledLoopRules.month.test(sp[0])) { } else if (ccn_datetime_precompiledLoopRules.month.test(sp[0])) {
loopRules = [2, RegExp.$1 == 'S', RegExp.$2, parseInt(RedExp.$3)]; loopRules = [1, RegExp.$1 == 'S', RegExp.$2, parseInt(RedExp.$3)];
} else if (ccn_datetime_precompiledLoopRules.week.test(sp[0])) { } else if (ccn_datetime_precompiledLoopRules.week.test(sp[0])) {
loopRules = [3]; loopRules = [2];
for (index in RegExp.$1) loopRules.push(RegExp.$1[index] == 'T'); for (var i = 0; i < 7; i++)
loopRules.push(RegExp.$1[i] == 'T');
loopRules.push(parseInt(RegExp.$2)); loopRules.push(parseInt(RegExp.$2));
} else if (ccn_datetime_precompiledLoopRules.day.test(sp[0])) { } else if (ccn_datetime_precompiledLoopRules.day.test(sp[0])) {
loopRules = [4, parseInt(RegExp.$1)]; loopRules = [3, parseInt(RegExp.$1)];
} else return undefined; } else return undefined;
@@ -74,6 +76,71 @@ function ccn_datetime_ResolveLoopRules4Event(strl) {
return undefined; return undefined;
} }
function ccn_datetime_LeapYearCountEx(endYear, includeThis, baseYear, includeBase) {
if (!includeThis) endYear--;
if (includeBase) baseYear--;
var endly = Math.floor(endYear / 4);
endly -= Math.floor(endYear / 100);
endly += Math.floor(endYear / 400);
var basely = Math.floor(baseYear / 4);
basely -= Math.floor(baseYear / 100);
basely += Math.floor(baseYear / 400);
return (endly - basely);
}
function ccn_datetime_DaysCount(year, month, day) {
var ly = ccn_datetime_LeapYearCountEx(year, false, 1, true);
var days = 365 * (year - 1);
days += ly;
for(var index = 1; index < month; index++)
days += ccn_datetime_monthDayCount[index - 1];
if (month > 2 && ccn_datetime_IsLeapYear(year))
days += 1;
days += day - 1;
return days;
}
function ccn_datetime_DayOfWeek(year, month, day) {
return ccn_datetime_DaysCount(year, month, day) % 7;
}
function ccn_datetime_GetDayInMonth(year, month, day) {
var days = ccn_datetime_monthDayCount[month - 1] + ((month == '2' && ccn_datetime_IsLeapYear(year)) ? 1 : 0);
var firstDayOfWeek = ccn_datetime_DayOfWeek(year, month, 1);
var dayOfWeek = (firstDayOfWeek + day - 1) % 7;
var dayForwards = day;
var dayBackwards = days - day + 1;
var weeksForward = Math.floor((dayForwards - 1) / 7) + 1;
var weeksBackwards = Math.floor((dayBackwards - 1) / 7) + 1;
return [dayForwards, dayBackwards, weeksForward, dayOfWeek, weeksBackwards, dayOfWeek];
}
function ccn_datetime_GetMonthWeekStatistics(year, month) {
var days = ccn_datetime_monthDayCount[month - 1] + ((month == '2' && ccn_datetime_IsLeapYear(year)) ? 1 : 0);
var firstDayOfWeek = ccn_datetime_DayOfWeek(year, month, 1);
var lastDayOfWeek = (firstDayOfWeek + days - 1) % 7;
var result = [4, 4, 4, 4, 4, 4, 4];
var remain = days % 7;
var week = firstDayOfWeek;
while (remain > 0) {
result[week % 7] += 1;
week++;
remain--;
}
return result;
}
function ccn_datetime_IsLeapYear(year) { function ccn_datetime_IsLeapYear(year) {
var isLeap = false; var isLeap = false;
if (year % 4 == 0) isLeap = true; if (year % 4 == 0) isLeap = true;

View File

@@ -50,15 +50,15 @@ function ccn_datetimepicker_SyncEx(pickerIndex) {
} }
} }
function ccn_datetimepicker_Set(pickerIndex, dt) { function ccn_datetimepicker_Set(pickerIndex, dt, isUTC) {
$('.datetimepicker-year[datetimepicker=' + pickerIndex + ']').val(dt.getFullYear()); $('.datetimepicker-year[datetimepicker=' + pickerIndex + ']').val(isUTC ? dt.getUTCFullYear() : dt.getFullYear());
$('.datetimepicker-month[datetimepicker=' + pickerIndex + ']').val(dt.getMonth() + 1); $('.datetimepicker-month[datetimepicker=' + pickerIndex + ']').val((isUTC ? dt.getUTCMonth() : dt.getMonth()) + 1);
$('.datetimepicker-day[datetimepicker=' + pickerIndex + ']').val(dt.getDate()); $('.datetimepicker-day[datetimepicker=' + pickerIndex + ']').val(isUTC ? dt.getUTCDate() : dt.getDate());
$('.datetimepicker-hour[datetimepicker=' + pickerIndex + ']').val(dt.getHours()); $('.datetimepicker-hour[datetimepicker=' + pickerIndex + ']').val(isUTC ? dt.getUTCHours() : dt.getHours());
$('.datetimepicker-minute[datetimepicker=' + pickerIndex + ']').val(dt.getMinutes()); $('.datetimepicker-minute[datetimepicker=' + pickerIndex + ']').val(isUTC ? dt.getUTCMinutes() : dt.getMinutes());
} }
function ccn_datetimepicker_Get(pickerIndex) { function ccn_datetimepicker_Get(pickerIndex, isUTC) {
year = $('.datetimepicker-year[datetimepicker=' + pickerIndex + ']').val(); year = $('.datetimepicker-year[datetimepicker=' + pickerIndex + ']').val();
month = $('.datetimepicker-month[datetimepicker=' + pickerIndex + ']').val(); month = $('.datetimepicker-month[datetimepicker=' + pickerIndex + ']').val();
day = $('.datetimepicker-day[datetimepicker=' + pickerIndex + ']').val(); day = $('.datetimepicker-day[datetimepicker=' + pickerIndex + ']').val();
@@ -70,5 +70,6 @@ function ccn_datetimepicker_Get(pickerIndex) {
if (IsUndefinedOrEmpty(hour)) hour = 0; if (IsUndefinedOrEmpty(hour)) hour = 0;
if (IsUndefinedOrEmpty(minute)) minute = 0; if (IsUndefinedOrEmpty(minute)) minute = 0;
return new Date(year, parseInt(month) - 1, day, hour, minute, 0, 0); if (isUTC) return new Date(Date.UTC(year, parseInt(month) - 1, day, hour, minute, 0, 0));
else return new Date(year, parseInt(month) - 1, day, hour, minute, 0, 0);
} }

View File

@@ -66,7 +66,7 @@ function ccn_calendar_calendar_LoadCalendarBody() {
} }
function ccn_calendar_calendar_Refresh() { function ccn_calendar_calendar_Refresh() {
gottenDateTime = ccn_datetimepicker_Get(1); gottenDateTime = ccn_datetimepicker_Get(1, false);
gottenYear = gottenDateTime.getFullYear(); gottenYear = gottenDateTime.getFullYear();
gottenMonth = gottenDateTime.getMonth() + 1; gottenMonth = gottenDateTime.getMonth() + 1;
} }
@@ -81,7 +81,7 @@ function ccn_calendar_calendar_AnalyseEvent() {
function ccn_calendar_calendar_Today() { function ccn_calendar_calendar_Today() {
var nowtime = new Date(); var nowtime = new Date();
ccn_datetimepicker_Set(1, nowtime); ccn_datetimepicker_Set(1, nowtime, false);
ccn_calendar_calendar_Refresh(); ccn_calendar_calendar_Refresh();
} }

View File

@@ -25,6 +25,15 @@ $(document).ready(function() {
// bind event // bind event
$('input[type=radio][name=loop-method]').click(ccn_event_RefreshRadioDiaplay); $('input[type=radio][name=loop-method]').click(ccn_event_RefreshRadioDiaplay);
$('input[type=radio][name=loop-end]').click(ccn_event_RefreshRadioDiaplay); $('input[type=radio][name=loop-end]').click(ccn_event_RefreshRadioDiaplay);
$('.datetimepicker-year[datetimepicker=1],.datetimepicker-month[datetimepicker=1],.datetimepicker-day[datetimepicker=1]').bind(
'input propertychange',
ccn_event_RefreshLoopMonthType
);
$('#ccn-event-btnSubmit').click(ccn_event_btnSubmit);
$('#ccn-event-btnCancel').click(ccn_event_btnCancel);
$('#ccn-event-btnSpot').click(ccn_event_btnSpot);
$('#ccn-event-btnFullDay').click(ccn_event_btnFullDay);
// init form // init form
ccn_event_Init(); ccn_event_Init();
@@ -91,7 +100,7 @@ function ccn_event_Init() {
} }
// in add mode, set as -1, otherwise try to match original data // in add mode, set as -1, otherwise try to match original data
// indexOf will return -1 if no matched item // indexOf will return -1 if no matched item
collectionDOM.val(isAdd ? '' : ccn_calendar_eventModal_editing[1]); collectionDOM.val(isAdd ? '' : ccn_event_editingEvent[1]);
// init start and end datetime // init start and end datetime
if (isAdd) { if (isAdd) {
@@ -100,18 +109,18 @@ function ccn_event_Init() {
currentDateTime.setMilliseconds(0); currentDateTime.setMilliseconds(0);
currentDateTime.setSeconds(0); currentDateTime.setSeconds(0);
currentDateTime.setMinutes(0); currentDateTime.setMinutes(0);
ccn_datetimepicker_Set(1, currentDateTime); ccn_datetimepicker_Set(1, currentDateTime, false);
// time span is 2 hours // time span is 2 hours
currentDateTime.setHours(currentDateTime.getHours() + 2); currentDateTime.setHours(currentDateTime.getHours() + 2);
ccn_datetimepicker_Set(2, currentDateTime); ccn_datetimepicker_Set(2, currentDateTime, false);
} else { } else {
// in update mode, match it with original data // in update mode, match it with original data
var originalDateTime = new Date(ccn_event_editingEvent[5] * 60000); var originalDateTime = new Date((ccn_event_editingEvent[5] + ccn_event_editingEvent[7]) * 60000);
ccn_datetimepicker_Set(1, originalDateTime); ccn_datetimepicker_Set(1, originalDateTime, true);
originalDateTime = new Date(ccn_event_editingEvent[6] * 60000); originalDateTime = new Date((ccn_event_editingEvent[6] + ccn_event_editingEvent[7]) * 60000);
ccn_datetimepicker_Set(2, originalDateTime); ccn_datetimepicker_Set(2, originalDateTime, true);
} }
// setup timezone here // setup timezone here
@@ -120,7 +129,7 @@ function ccn_event_Init() {
$('#ccn-event-timezone-radioKeep').prop('checked', true); // give a default value $('#ccn-event-timezone-radioKeep').prop('checked', true); // give a default value
var nowtime = new Date(); var nowtime = new Date();
SmarterShowHide( SmarterShowHide(
(!isAdd) && nowtime.getTimezoneOffset() != ccn_event_editingEvent[7], (!isAdd) && (-nowtime.getTimezoneOffset()) != ccn_event_editingEvent[7],
$('#ccn-event-boxTimezone') $('#ccn-event-boxTimezone')
); );
@@ -133,23 +142,26 @@ function ccn_event_Init() {
// give some value with a default value // give some value with a default value
$('#ccn-event-loopMonth-radioA').prop('checked', true); $('#ccn-event-loopMonth-radioA').prop('checked', true);
var weekDate = undefined; $('#ccn-event-loopWeek-check' + (nowtime.getWeekday() + 1)).prop('checked', true);
if (isAdd) weekDate = nowtime; $('#ccn-event-strictMode-radioStrict').prop('checked', true);
else weekDate = new Date(ccn_event_editingEvent[5] * 60000);
$('#ccn-event-loopWeek-check' + (weekDate.getDay() + 1)).prop('checked', true);
// real process // real process
if (isAdd) $('#ccn-event-radioLoopNever').prop('checked', true); if (isAdd) {
else { $('#ccn-event-radioLoopNever').prop('checked', true);
} else {
switch(data[0][0]) { switch(data[0][0]) {
case 0: case 0:
$('#ccn-event-radioLoopYear').prop('checked', true); $('#ccn-event-radioLoopYear').prop('checked', true);
$('#ccn-event-loopYear-inputSpan').val(data[0][2]); $('#ccn-event-loopYear-inputSpan').val(data[0][2]);
if (data[0][1]) $('#ccn-event-strictMode-radioStrict').prop('checked', true);
else $('#ccn-event-strictMode-radioRough').prop('checked', true);
break; break;
case 1: case 1:
$('#ccn-event-radioLoopMonth').prop('checked', true); $('#ccn-event-radioLoopMonth').prop('checked', true);
$('#ccn-event-loopMonth-inputSpan').val(data[0][3]); $('#ccn-event-loopMonth-inputSpan').val(data[0][3]);
$('#ccn-event-loopMonth-radio' + data[0][2]).prop('checked', true); $('#ccn-event-loopMonth-radio' + data[0][2]).prop('checked', true);
if (data[0][1]) $('#ccn-event-strictMode-radioStrict').prop('checked', true);
else $('#ccn-event-strictMode-radioRough').prop('checked', true);
break; break;
case 2: case 2:
$('#ccn-event-radioLoopWeek').prop('checked', true); $('#ccn-event-radioLoopWeek').prop('checked', true);
@@ -165,9 +177,11 @@ function ccn_event_Init() {
} }
} }
// give some item a default value
ccn_datetimepicker_Set(3, nowtime, false);
if (isAdd) { if (isAdd) {
$('#ccn-event-loopStop-radioForever').prop('checked', true); $('#ccn-event-loopStop-radioForever').prop('checked', true);
ccn_datetimepicker_Set(3, nowtime);
} else { } else {
switch(data[1][0]) { switch(data[1][0]) {
case 0: case 0:
@@ -175,8 +189,8 @@ function ccn_event_Init() {
break; break;
case 1: case 1:
$('#ccn-event-loopStop-radioDateTime').prop('checked', true); $('#ccn-event-loopStop-radioDateTime').prop('checked', true);
var stopDatetime = new Date(data[1][1] * 60000); var stopDatetime = new Date((data[1][1] + ccn_event_editingEvent[7]) * 60000);
ccn_datetimepicker_Set(3, stopDatetime); ccn_datetimepicker_Set(3, stopDatetime, true);
break; break;
case 2: case 2:
$('#ccn-event-loopStop-radioTimes').prop('checked', true); $('#ccn-event-loopStop-radioTimes').prop('checked', true);
@@ -212,11 +226,163 @@ function ccn_event_RefreshRadioDiaplay() {
} }
function ccn_event_RefreshLoopMonthType() { function ccn_event_RefreshLoopMonthType() {
var picker = ccn_datetimepicker_Get(1, false);
var data = ccn_datetime_GetDayInMonth(picker.getFullYear(), picker.getMonth() + 1, picker.getDate());
$('#ccn-event-loopMonth-textA').text($.i18n.prop('ccn-i18n-event-loopWeek-optionA').format(data[0]));
$('#ccn-event-loopMonth-textB').text($.i18n.prop('ccn-i18n-event-loopWeek-optionB').format(data[1]));
$('#ccn-event-loopMonth-textC').text($.i18n.prop('ccn-i18n-event-loopWeek-optionC').format(data[2], data[3] + 1));
$('#ccn-event-loopMonth-textD').text($.i18n.prop('ccn-i18n-event-loopWeek-optionD').format(data[4], data[5] + 1));
} }
// return undefined to indicate an error // return undefined to indicate an error
function ccn_event_Get() { // or
// [belongTo, title, description, eventDateTimeStart, eventDateTimeEnd, timezoneOffset, loopRules]
function ccn_event_GetForm() {
// basic
var title = $('#ccn-event-inputTitle').val();
if (title == '') return undefined;
var description = $('#ccn-event-inputDescription').val();
if (description == '') return undefined;
var belongTo = $('#ccn-event-inputCollection').val();
if (belongTo == null) return undefined; // if no selected item, val return null, not undefined
var isAdd = typeof(ccn_event_editingEvent) == 'undefined';
var keepTimezone = $('#ccn-event-timezone-radioKeep').prop('checked');
var isStrict = $('#ccn-event-strictMode-radioStrict').prop('checked');
// time
var eventDateTimeStart = undefined;
var eventDateTimeEnd = undefined;
var timezoneOffset = undefined;
if ((!isAdd) && (!keepTimezone)) {
// get datetime as utc, then minus original timezone to get unix timestamp
timezoneOffset = ccn_event_editingEvent[7]; // keep timezone
eventDateTimeStart = Math.floor(ccn_datetimepicker_Get(1, true).getTime() / 60000) - timezoneOffset;
eventDateTimeEnd = Math.floor(ccn_datetimepicker_Get(2, true).getTime() / 60000) - timezoneOffset;
} else {
// use my timezone, resolve presented data as my local time
var cache = ccn_datetimepicker_Get(1, false);
timezoneOffset = -cache.getTimezoneOffset();
eventDateTimeStart = Math.floor(cache.getTime() / 60000);
eventDateTimeEnd = Math.floor(ccn_datetimepicker_Get(2, false).getTime() / 60000);
}
// loopRules
var loopRules = undefined;
if ($('#ccn-event-radioLoopNever').prop('checked')) {
loopRules = "";
} else if ($('#ccn-event-radioLoopDay').prop('checked')) {
loopRules = "D{0}".format($('#ccn-event-loopDay-inputSpan').val());
} else if ($('#ccn-event-radioLoopWeek').prop('checked')) {
var cache = ""
for(var i = 1; i < 8; i++)
cache += $('#ccn-event-loopWeek-check' + i).prop('checked') ? 'T' : 'F';
loopRules = 'W{0}{1}'.format(
cache,
$('#ccn-event-loopWeek-inputSpan').val()
);
} else if ($('#ccn-event-radioLoopMonth').prop('checked')) {
var cache = undefined;
if ($('#ccn-event-loopMonth-radioA').prop('checked')) cache='A';
else if ($('#ccn-event-loopMonth-radioB').prop('checked')) cache='B';
else if ($('#ccn-event-loopMonth-radioC').prop('checked')) cache='C';
else if ($('#ccn-event-loopMonth-radioD').prop('checked')) cache='D';
else return undefined;
loopRules = "M{0}{1}{2}".format(
isStrict ? "S" : "R",
cache,
$('#ccn-event-loopMonth-inputSpan').val()
);
} else if ($('#ccn-event-radioLoopYear').prop('checked')) {
loopRules = "Y{0}{1}".format(
isStrict ? "S" : "R",
$('#ccn-event-loopDay-inputSpan').val()
);
}
// no need to process stop if this is not a loop event
if (loopRules != "") {
loopRules += '-';
if ($('#ccn-event-loopStop-radioForever').prop('checked')) {
loopRules += 'F';
} else if ($('#ccn-event-loopStop-radioDateTime').prop('checked')) {
var timestamp = undefined;
if ((!isAdd) && (!keepTimezone)) {
// keep timezone
var cache = ccn_datetimepicker_Get(3, true);
cache.setUTCHours(23);
cache.setUTCMinutes(59);
timestamp = Math.floor(cache.getTime() / 60000) - timezoneOffset;
} else {
// use my timezone
timestamp = Math.floor(ccn_datetimepicker_Get(3, false).getTime() / 60000);
}
loopRules += 'D{0}'.format(timestamp);
} else if ($('#ccn-event-loopStop-radioTimes').prop('checked')) {
loopRules += 'T{0}'.format($('#ccn-event-loopStop-inputTimes').val());
}
}
return [belongTo, title, description, eventDateTimeStart, eventDateTimeEnd, timezoneOffset, loopRules];
}
function ccn_event_btnSpot() {
var datetime = ccn_datetimepicker_Get(1, false);
datetime.setMinutes(datetime.getMinutes() + 1);
ccn_datetimepicker_Set(2, datetime, false);
}
function ccn_event_btnFullDay() {
var datetime = ccn_datetimepicker_Get(1, false);
datetime.setMinutes(0);
datetime.setHours(0);
ccn_datetimepicker_Set(1, datetime, false);
datetime.setMinutes(59);
datetime.setHours(23);
ccn_datetimepicker_Set(2, datetime, false);
}
function ccn_event_btnCancel() {
window.location.href = '/web/calendar';
}
function ccn_event_btnSubmit() {
var submitData = ccn_event_GetForm();
if (typeof(submitData) == 'undefined') {
ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-form"));
return;
}
var isAdd = typeof(ccn_event_editingEvent) == 'undefined';
if (isAdd) {
var result = ccn_api_calendar_add(
submitData[0],
submitData[1],
submitData[2],
submitData[3],
submitData[4],
submitData[6],
submitData[5]
);
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-add"));
else window.location.href = '/web/calendar';
} else {
var result = ccn_api_calendar_update(
ccn_event_editingEvent[0],
ccn_event_editingEvent[1] == submitData[0] ? undefined : submitData[0],
ccn_event_editingEvent[2] == submitData[1] ? undefined : submitData[1],
ccn_event_editingEvent[3] == submitData[2] ? undefined : submitData[2],
ccn_event_editingEvent[5] == submitData[3] ? undefined : submitData[3],
ccn_event_editingEvent[6] == submitData[4] ? undefined : submitData[4],
ccn_event_editingEvent[8] == submitData[6] ? undefined : submitData[6],
ccn_event_editingEvent[7] == submitData[5] ? undefined : submitData[5],
ccn_event_editingEvent[4]
);
if (typeof(result) == 'undefined') ccn_messagebox_Show($.i18n.prop("ccn-i18n-js-fail-update"));
else window.location.href = '/web/calendar';
}
} }

View File

@@ -50,3 +50,19 @@ function SmarterShowHide(boolean, element) {
if (boolean) element.show(); if (boolean) element.show();
else element.hide(); else element.hide();
} }
String.prototype.format = function() {
var e = arguments;
return !!this && this.replace(
/\{(\d+)\}/g,
function (t, n) {
return e[n].toString() ? e[n].toString() : t;
}
);
};
Date.prototype.getWeekday = function() {
var temp = this.getDay();
if (temp == 0) return 6;
else return temp - 1;
};