Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F7056868
calendar.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
36 KB
Referenced Files
None
Subscribers
None
calendar.js
View Options
/*
+-------------------------------------------------------------------------+
| Javascript for the Calendar Plugin |
| Version 0.3 beta |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License version 2 |
| as published by the Free Software Foundation. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along |
| with this program; if not, write to the Free Software Foundation, Inc., |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| |
+-------------------------------------------------------------------------+
| Author: Lazlo Westerhof <hello@lazlo.me> |
| Thomas Bruederli <roundcube@gmail.com> |
+-------------------------------------------------------------------------+
*/
/* calendar initialization */
window
.
rcmail
&&
rcmail
.
addEventListener
(
'init'
,
function
(
evt
)
{
// quote html entities
function
Q
(
str
)
{
return
String
(
str
).
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
).
replace
(
/"/g
,
'"'
);
}
// php equivalent
function
nl2br
(
str
)
{
return
String
(
str
).
replace
(
/\n/g
,
"<br/>"
);
}
// Roundcube calendar client class
function
rcube_calendar
(
settings
)
{
// member vars
this
.
settings
=
settings
;
this
.
alarm_ids
=
[];
this
.
alarm_dialog
=
null
;
this
.
snooze_popup
=
null
;
this
.
dismiss_link
=
null
// private vars
var
me
=
this
;
var
day_clicked
=
day_clicked_ts
=
0
;
var
ignore_click
=
false
;
// create a nice human-readable string for the date/time range
var
event_date_text
=
function
(
event
)
{
var
fromto
,
duration
=
event
.
end
.
getTime
()
/
1000
-
event
.
start
.
getTime
()
/
1000
;
if
(
event
.
allDay
)
fromto
=
$
.
fullCalendar
.
formatDate
(
event
.
start
,
settings
[
'date_format'
])
+
(
duration
>
86400
?
' — '
+
$
.
fullCalendar
.
formatDate
(
event
.
end
,
settings
[
'date_format'
])
:
''
);
else
if
(
duration
<
86400
&&
event
.
start
.
getDay
()
==
event
.
end
.
getDay
())
fromto
=
$
.
fullCalendar
.
formatDate
(
event
.
start
,
settings
[
'date_format'
])
+
' '
+
$
.
fullCalendar
.
formatDate
(
event
.
start
,
settings
[
'time_format'
])
+
' — '
+
$
.
fullCalendar
.
formatDate
(
event
.
end
,
settings
[
'time_format'
]);
else
fromto
=
$
.
fullCalendar
.
formatDate
(
event
.
start
,
settings
[
'date_format'
])
+
' '
+
$
.
fullCalendar
.
formatDate
(
event
.
start
,
settings
[
'time_format'
])
+
' — '
+
$
.
fullCalendar
.
formatDate
(
event
.
end
,
settings
[
'date_format'
])
+
' '
+
$
.
fullCalendar
.
formatDate
(
event
.
end
,
settings
[
'time_format'
]);
return
fromto
;
};
// event details dialog (show only)
var
event_show_dialog
=
function
(
event
)
{
var
$dialog
=
$
(
"#eventshow"
);
var
calendar
=
event
.
calendar
&&
me
.
calendars
[
event
.
calendar
]
?
me
.
calendars
[
event
.
calendar
]
:
{
editable
:
false
};
$dialog
.
find
(
'div.event-section, div.event-line'
).
hide
();
$
(
'#event-title'
).
html
(
Q
(
event
.
title
)).
show
();
if
(
event
.
location
)
$
(
'#event-location'
).
html
(
'@ '
+
Q
(
event
.
location
)).
show
();
if
(
event
.
description
)
$
(
'#event-description'
).
show
().
children
(
'.event-text'
).
html
(
nl2br
(
Q
(
event
.
description
)));
// TODO: format HTML with clickable links and stuff
// render from-to in a nice human-readable way
$
(
'#event-date'
).
html
(
Q
(
event_date_text
(
event
))).
show
();
if
(
event
.
recurrence
&&
event
.
recurrence_text
)
$
(
'#event-repeat'
).
show
().
children
(
'.event-text'
).
html
(
Q
(
event
.
recurrence_text
));
if
(
event
.
alarms
&&
event
.
alarms_text
)
$
(
'#event-alarm'
).
show
().
children
(
'.event-text'
).
html
(
Q
(
event
.
alarms_text
));
if
(
calendar
.
name
)
$
(
'#event-calendar'
).
show
().
children
(
'.event-text'
).
html
(
Q
(
calendar
.
name
)).
removeClass
().
addClass
(
'event-text'
).
addClass
(
'cal-'
+
calendar
.
id
);
if
(
event
.
categories
)
$
(
'#event-category'
).
show
().
children
(
'.event-text'
).
html
(
Q
(
event
.
categories
)).
removeClass
().
addClass
(
'event-text '
+
event
.
className
);
if
(
event
.
free_busy
)
$
(
'#event-free-busy'
).
show
().
children
(
'.event-text'
).
html
(
Q
(
rcmail
.
gettext
(
event
.
free_busy
,
'calendar'
)));
if
(
event
.
priority
!=
1
)
{
var
priolabels
=
{
0
:
rcmail
.
gettext
(
'low'
),
1
:
rcmail
.
gettext
(
'normal'
),
2
:
rcmail
.
gettext
(
'high'
)
};
$
(
'#event-priority'
).
show
().
children
(
'.event-text'
).
html
(
Q
(
priolabels
[
event
.
priority
]));
}
if
(
event
.
sensitivity
!=
0
)
{
var
sensitivitylabels
=
{
0
:
rcmail
.
gettext
(
'public'
),
1
:
rcmail
.
gettext
(
'private'
),
2
:
rcmail
.
gettext
(
'confidential'
)
};
$
(
'#event-sensitivity'
).
show
().
children
(
'.event-text'
).
html
(
Q
(
sensitivitylabels
[
event
.
sensitivity
]));
}
var
buttons
=
{};
if
(
calendar
.
editable
&&
event
.
editable
!==
false
)
{
buttons
[
rcmail
.
gettext
(
'edit'
,
'calendar'
)]
=
function
()
{
event_edit_dialog
(
'edit'
,
event
);
};
buttons
[
rcmail
.
gettext
(
'remove'
,
'calendar'
)]
=
function
()
{
me
.
delete_event
(
event
);
$dialog
.
dialog
(
'close'
);
};
}
else
{
buttons
[
rcmail
.
gettext
(
'close'
,
'calendar'
)]
=
function
(){
$dialog
.
dialog
(
'close'
);
};
}
// open jquery UI dialog
$dialog
.
dialog
({
modal
:
false
,
resizable
:
true
,
title
:
null
,
close
:
function
()
{
$dialog
.
dialog
(
'destroy'
).
hide
();
},
buttons
:
buttons
,
minWidth
:
320
,
width
:
420
}).
show
();
$
(
'<a>'
)
.
attr
(
'href'
,
'#'
)
.
html
(
'More Options'
)
.
addClass
(
'dropdown-link'
)
.
click
(
function
(){
return
false
;
})
.
insertBefore
(
$dialog
.
parent
().
find
(
'.ui-dialog-buttonset'
).
children
().
first
());
};
// bring up the event dialog (jquery-ui popup)
var
event_edit_dialog
=
function
(
action
,
event
)
{
// close show dialog first
$
(
"#eventshow"
).
dialog
(
'close'
);
var
$dialog
=
$
(
"#eventedit"
);
var
calendar
=
event
.
calendar
&&
me
.
calendars
[
event
.
calendar
]
?
me
.
calendars
[
event
.
calendar
]
:
{
editable
:
action
==
'new'
};
// reset dialog first, enable/disable fields according to editable state
$
(
'#eventtabs'
).
get
(
0
).
reset
();
$
(
'#calendar-select'
)[(
action
==
'new'
?
'show'
:
'hide'
)]();
// event details
var
title
=
$
(
'#edit-title'
).
val
(
event
.
title
);
var
location
=
$
(
'#edit-location'
).
val
(
event
.
location
);
var
description
=
$
(
'#edit-description'
).
val
(
event
.
description
);
var
categories
=
$
(
'#edit-categories'
).
val
(
event
.
categories
);
var
calendars
=
$
(
'#edit-calendar'
).
val
(
event
.
calendar
);
var
freebusy
=
$
(
'#edit-free-busy'
).
val
(
event
.
free_busy
);
var
priority
=
$
(
'#edit-priority'
).
val
(
event
.
priority
);
var
sensitivity
=
$
(
'#edit-sensitivity'
).
val
(
event
.
sensitivity
);
var
duration
=
Math
.
round
((
event
.
end
.
getTime
()
-
event
.
start
.
getTime
())
/
1000
);
var
startdate
=
$
(
'#edit-startdate'
).
val
(
$
.
fullCalendar
.
formatDate
(
event
.
start
,
settings
[
'date_format'
])).
data
(
'duration'
,
duration
);
var
starttime
=
$
(
'#edit-starttime'
).
val
(
$
.
fullCalendar
.
formatDate
(
event
.
start
,
settings
[
'time_format'
])).
show
();
var
enddate
=
$
(
'#edit-enddate'
).
val
(
$
.
fullCalendar
.
formatDate
(
event
.
end
,
settings
[
'date_format'
]));
var
endtime
=
$
(
'#edit-endtime'
).
val
(
$
.
fullCalendar
.
formatDate
(
event
.
end
,
settings
[
'time_format'
])).
show
();
var
allday
=
$
(
'#edit-allday'
).
get
(
0
);
if
(
event
.
allDay
)
{
starttime
.
val
(
"00:00"
).
hide
();
endtime
.
val
(
"23:59"
).
hide
();
allday
.
checked
=
true
;
}
else
{
allday
.
checked
=
false
;
}
// set alarm(s)
// TODO: support multiple alarm entries
if
(
event
.
alarms
)
{
if
(
typeof
event
.
alarms
==
'string'
)
event
.
alarms
=
event
.
alarms
.
split
(
';'
);
for
(
var
alarm
,
i
=
0
;
i
<
event
.
alarms
.
length
;
i
++
)
{
alarm
=
String
(
event
.
alarms
[
i
]).
split
(
':'
);
if
(
!
alarm
[
1
]
&&
alarm
[
0
])
alarm
[
1
]
=
'DISPLAY'
;
$
(
'select.edit-alarm-type'
).
val
(
alarm
[
1
]);
if
(
alarm
[
0
].
match
(
/@(\d+)/
))
{
var
ondate
=
new
Date
(
parseInt
(
RegExp
.
$1
)
*
1000
);
$
(
'select.edit-alarm-offset'
).
val
(
'@'
);
$
(
'input.edit-alarm-date'
).
val
(
$
.
fullCalendar
.
formatDate
(
ondate
,
settings
[
'date_format'
]));
$
(
'input.edit-alarm-time'
).
val
(
$
.
fullCalendar
.
formatDate
(
ondate
,
settings
[
'time_format'
]));
}
else
if
(
alarm
[
0
].
match
(
/([-+])(\d+)([MHD])/
))
{
$
(
'input.edit-alarm-value'
).
val
(
RegExp
.
$2
);
$
(
'select.edit-alarm-offset'
).
val
(
''
+
RegExp
.
$1
+
RegExp
.
$3
);
}
}
}
// set correct visibility by triggering onchange handlers
$
(
'select.edit-alarm-type, select.edit-alarm-offset'
).
change
();
// enable/disable alarm property according to backend support
$
(
'#edit-alarms'
)[(
calendar
.
alarms
?
'show'
:
'hide'
)]();
// set recurrence form
var
recurrence
=
$
(
'#edit-recurrence-frequency'
).
val
(
event
.
recurrence
?
event
.
recurrence
.
FREQ
:
''
).
change
();
var
interval
=
$
(
'select.edit-recurrence-interval'
).
val
(
event
.
recurrence
?
event
.
recurrence
.
INTERVAL
:
1
);
var
rrtimes
=
$
(
'#edit-recurrence-repeat-times'
).
val
(
event
.
recurrence
?
event
.
recurrence
.
COUNT
:
1
);
var
rrenddate
=
$
(
'#edit-recurrence-enddate'
).
val
(
event
.
recurrence
&&
event
.
recurrence
.
UNTIL
?
$
.
fullCalendar
.
formatDate
(
new
Date
(
event
.
recurrence
.
UNTIL
*
1000
),
settings
[
'date_format'
])
:
''
);
$
(
'input.edit-recurrence-until:checked'
).
prop
(
'checked'
,
false
);
var
weekdays
=
[
'SU'
,
'MO'
,
'TU'
,
'WE'
,
'TH'
,
'FR'
,
'SA'
];
var
rrepeat_id
=
'#edit-recurrence-repeat-forever'
;
if
(
event
.
recurrence
&&
event
.
recurrence
.
COUNT
)
rrepeat_id
=
'#edit-recurrence-repeat-count'
;
else
if
(
event
.
recurrence
&&
event
.
recurrence
.
UNTIL
)
rrepeat_id
=
'#edit-recurrence-repeat-until'
;
$
(
rrepeat_id
).
prop
(
'checked'
,
true
);
if
(
event
.
recurrence
&&
event
.
recurrence
.
BYDAY
&&
event
.
recurrence
.
FREQ
==
'WEEKLY'
)
{
var
wdays
=
event
.
recurrence
.
BYDAY
.
split
(
','
);
$
(
'input.edit-recurrence-weekly-byday'
).
val
(
wdays
);
}
else
if
(
event
.
start
)
{
$
(
'input.edit-recurrence-weekly-byday'
).
val
([
weekdays
[
event
.
start
.
getDay
()]]);
}
if
(
event
.
recurrence
&&
event
.
recurrence
.
BYMONTHDAY
)
{
$
(
'input.edit-recurrence-monthly-bymonthday'
).
val
(
String
(
event
.
recurrence
.
BYMONTHDAY
).
split
(
','
));
$
(
'input.edit-recurrence-monthly-mode'
).
val
([
'BYMONTHDAY'
]);
}
else
if
(
event
.
start
)
{
$
(
'input.edit-recurrence-monthly-bymonthday'
).
val
([
event
.
start
.
getDate
()]);
}
if
(
event
.
recurrence
&&
event
.
recurrence
.
BYDAY
&&
(
event
.
recurrence
.
FREQ
==
'MONTHLY'
||
event
.
recurrence
.
FREQ
==
'YEARLY'
))
{
var
byday
,
section
=
event
.
recurrence
.
FREQ
.
toLowerCase
();
if
((
byday
=
String
(
event
.
recurrence
.
BYDAY
).
match
(
/(-?[1-4])([A-Z]+)/
)))
{
$
(
'#edit-recurrence-'
+
section
+
'-prefix'
).
val
(
byday
[
1
]);
$
(
'#edit-recurrence-'
+
section
+
'-byday'
).
val
(
byday
[
2
]);
}
$
(
'input.edit-recurrence-'
+
section
+
'-mode'
).
val
([
'BYDAY'
]);
}
else
if
(
event
.
start
)
{
$
(
'#edit-recurrence-monthly-byday'
).
val
(
weekdays
[
event
.
start
.
getDay
()]);
}
if
(
event
.
recurrence
&&
event
.
recurrence
.
BYMONTH
)
{
$
(
'input.edit-recurrence-yearly-bymonth'
).
val
(
String
(
event
.
recurrence
.
BYMONTH
).
split
(
','
));
}
else
if
(
event
.
start
)
{
$
(
'input.edit-recurrence-yearly-bymonth'
).
val
([
String
(
event
.
start
.
getMonth
()
+
1
)]);
}
// buttons
var
buttons
=
{};
buttons
[
rcmail
.
gettext
(
'save'
,
'calendar'
)]
=
function
()
{
var
start
=
me
.
parse_datetime
(
starttime
.
val
(),
startdate
.
val
());
var
end
=
me
.
parse_datetime
(
endtime
.
val
(),
enddate
.
val
());
// post data to server
var
data
=
{
start
:
start
.
getTime
()
/
1000
,
end
:
end
.
getTime
()
/
1000
,
allday
:
allday
.
checked
?
1
:
0
,
title
:
title
.
val
(),
description
:
description
.
val
(),
location
:
location
.
val
(),
categories
:
categories
.
val
(),
free_busy
:
freebusy
.
val
(),
priority
:
priority
.
val
(),
sensitivity
:
sensitivity
.
val
(),
recurrence
:
''
,
alarms
:
''
,
};
// serialize alarm settings
// TODO: support multiple alarm entries
var
alarm
=
$
(
'select.edit-alarm-type'
).
val
();
if
(
alarm
)
{
var
val
,
offset
=
$
(
'select.edit-alarm-offset'
).
val
();
if
(
offset
==
'@'
)
data
.
alarms
=
'@'
+
(
me
.
parse_datetime
(
$
(
'input.edit-alarm-time'
).
val
(),
$
(
'input.edit-alarm-date'
).
val
()).
getTime
()
/
1000
)
+
':'
+
alarm
;
else
if
((
val
=
parseInt
(
$
(
'input.edit-alarm-value'
).
val
()))
&&
!
isNaN
(
val
)
&&
val
>=
0
)
data
.
alarms
=
offset
[
0
]
+
val
+
offset
[
1
]
+
':'
+
alarm
;
}
// gather recurrence settings
var
freq
;
if
((
freq
=
recurrence
.
val
())
!=
''
)
{
data
.
recurrence
=
{
FREQ
:
freq
,
INTERVAL
:
$
(
'#edit-recurrence-interval-'
+
freq
.
toLowerCase
()).
val
()
};
var
until
=
$
(
'input.edit-recurrence-until:checked'
).
val
();
if
(
until
==
'count'
)
data
.
recurrence
.
COUNT
=
rrtimes
.
val
();
else
if
(
until
==
'until'
)
data
.
recurrence
.
UNTIL
=
me
.
parse_datetime
(
endtime
.
val
(),
rrenddate
.
val
()).
getTime
()
/
1000
;
if
(
freq
==
'WEEKLY'
)
{
var
byday
=
[];
$
(
'input.edit-recurrence-weekly-byday:checked'
).
each
(
function
(){
byday
.
push
(
this
.
value
);
});
data
.
recurrence
.
BYDAY
=
byday
.
join
(
','
);
}
else
if
(
freq
==
'MONTHLY'
)
{
var
mode
=
$
(
'input.edit-recurrence-monthly-mode:checked'
).
val
(),
bymonday
=
[];
if
(
mode
==
'BYMONTHDAY'
)
{
$
(
'input.edit-recurrence-monthly-bymonthday:checked'
).
each
(
function
(){
bymonday
.
push
(
this
.
value
);
});
data
.
recurrence
.
BYMONTHDAY
=
bymonday
.
join
(
','
);
}
else
data
.
recurrence
.
BYDAY
=
$
(
'#edit-recurrence-monthly-prefix'
).
val
()
+
$
(
'#edit-recurrence-monthly-byday'
).
val
();
}
else
if
(
freq
==
'YEARLY'
)
{
var
byday
,
bymonth
=
[];
$
(
'input.edit-recurrence-yearly-bymonth:checked'
).
each
(
function
(){
bymonth
.
push
(
this
.
value
);
});
data
.
recurrence
.
BYMONTH
=
bymonth
.
join
(
','
);
if
((
byday
=
$
(
'#edit-recurrence-yearly-byday'
).
val
()))
data
.
recurrence
.
BYDAY
=
$
(
'#edit-recurrence-yearly-prefix'
).
val
()
+
byday
;
}
}
if
(
event
.
id
)
data
.
id
=
event
.
id
;
else
data
.
calendar
=
calendars
.
val
();
rcmail
.
http_post
(
'plugin.event'
,
{
action
:
action
,
e
:
data
});
$dialog
.
dialog
(
"close"
);
};
if
(
event
.
id
)
{
buttons
[
rcmail
.
gettext
(
'remove'
,
'calendar'
)]
=
function
()
{
me
.
delete_event
(
event
);
$dialog
.
dialog
(
'close'
);
};
}
buttons
[
rcmail
.
gettext
(
'cancel'
,
'calendar'
)]
=
function
()
{
$dialog
.
dialog
(
"close"
);
};
// show/hide tabs according to calendar's feature support
$
(
'#edit-tab-attendees'
)[(
calendar
.
attendees
?
'show'
:
'hide'
)]();
$
(
'#edit-tab-attachments'
)[(
calendar
.
attachments
?
'show'
:
'hide'
)]();
// activate the first tab
$
(
'#eventtabs'
).
tabs
(
'select'
,
0
);
// open jquery UI dialog
$dialog
.
dialog
({
modal
:
true
,
resizable
:
true
,
title
:
rcmail
.
gettext
((
action
==
'edit'
?
'edit_event'
:
'new_event'
),
'calendar'
),
close
:
function
()
{
$dialog
.
dialog
(
"destroy"
).
hide
();
},
buttons
:
buttons
,
minWidth
:
440
,
width
:
480
}).
show
();
title
.
select
();
};
// mouse-click handler to check if the show dialog is still open and prevent default action
var
dialog_check
=
function
(
e
)
{
var
showd
=
$
(
"#eventshow"
);
if
(
showd
.
is
(
':visible'
)
&&
!
$
(
e
.
target
).
closest
(
'.ui-dialog'
).
length
)
{
showd
.
dialog
(
'close'
);
e
.
stopImmediatePropagation
();
ignore_click
=
true
;
return
false
;
}
else
if
(
ignore_click
)
{
window
.
setTimeout
(
function
(){
ignore_click
=
false
;
},
20
);
return
false
;
}
return
true
;
};
// general datepicker settings
this
.
datepicker_settings
=
{
// translate from fullcalendar format to datepicker format
dateFormat
:
settings
[
'date_format'
].
replace
(
/M/g
,
'm'
).
replace
(
/mmmmm/
,
'MM'
).
replace
(
/mmm/
,
'M'
).
replace
(
/dddd/
,
'DD'
).
replace
(
/ddd/
,
'D'
).
replace
(
/yy/g
,
'y'
),
firstDay
:
settings
[
'first_day'
],
dayNamesMin
:
settings
[
'days_short'
],
monthNames
:
settings
[
'months'
],
monthNamesShort
:
settings
[
'months'
],
changeMonth
:
false
,
showOtherMonths
:
true
,
selectOtherMonths
:
true
,
};
// from time and date strings to a real date object
this
.
parse_datetime
=
function
(
time
,
date
)
{
// we use the utility function from datepicker to parse dates
var
date
=
$
.
datepicker
.
parseDate
(
me
.
datepicker_settings
.
dateFormat
,
date
,
me
.
datepicker_settings
);
var
time_arr
=
time
.
split
(
/[:.]/
);
if
(
!
isNaN
(
time_arr
[
0
]))
date
.
setHours
(
time_arr
[
0
]);
if
(
!
isNaN
(
time_arr
[
1
]))
date
.
setMinutes
(
time_arr
[
1
]);
return
date
;
};
// public method to bring up the new event dialog
this
.
add_event
=
function
()
{
if
(
this
.
selected_calendar
)
{
var
now
=
new
Date
();
var
date
=
$
(
'#calendar'
).
fullCalendar
(
'getDate'
)
||
now
;
date
.
setHours
(
now
.
getHours
()
+
1
);
date
.
setMinutes
(
0
);
var
end
=
new
Date
(
date
.
getTime
());
end
.
setHours
(
date
.
getHours
()
+
1
);
event_edit_dialog
(
'new'
,
{
start
:
date
,
end
:
end
,
allDay
:
false
,
calendar
:
this
.
selected_calendar
});
}
};
// delete the given event after showing a confirmation dialog
this
.
delete_event
=
function
(
event
)
{
// send remove request to plugin
if
(
confirm
(
rcmail
.
gettext
(
'deleteventconfirm'
,
'calendar'
)))
{
rcmail
.
http_post
(
'plugin.event'
,
{
action
:
'remove'
,
e
:
{
id
:
event
.
id
}
});
return
true
;
}
return
false
;
};
// display a notification for the given pending alarms
this
.
display_alarms
=
function
(
alarms
)
{
// clear old alert first
if
(
this
.
alarm_dialog
)
this
.
alarm_dialog
.
dialog
(
'destroy'
);
this
.
alarm_dialog
=
$
(
'<div>'
).
attr
(
'id'
,
'alarm-display'
);
var
actions
,
adismiss
,
asnooze
,
alarm
,
html
,
event_ids
=
[];
for
(
var
actions
,
html
,
alarm
,
i
=
0
;
i
<
alarms
.
length
;
i
++
)
{
alarm
=
alarms
[
i
];
alarm
.
start
=
new
Date
(
alarm
.
start
*
1000
);
alarm
.
end
=
new
Date
(
alarm
.
end
*
1000
);
event_ids
.
push
(
alarm
.
id
);
html
=
'<h3 class="event-title">'
+
Q
(
alarm
.
title
)
+
'</h3>'
;
html
+=
'<div class="event-section">'
+
Q
(
alarm
.
location
)
+
'</div>'
;
html
+=
'<div class="event-section">'
+
Q
(
event_date_text
(
alarm
))
+
'</div>'
;
adismiss
=
$
(
'<a href="#" class="alarm-action-dismiss"></a>'
).
html
(
rcmail
.
gettext
(
'dismiss'
,
'calendar'
)).
click
(
function
(){
me
.
dismiss_link
=
$
(
this
);
me
.
dismiss_alarm
(
me
.
dismiss_link
.
data
(
'id'
),
0
);
});
asnooze
=
$
(
'<a href="#" class="alarm-action-snooze"></a>'
).
html
(
rcmail
.
gettext
(
'snooze'
,
'calendar'
)).
click
(
function
(){
me
.
snooze_dropdown
(
$
(
this
));
});
actions
=
$
(
'<div>'
).
addClass
(
'alarm-actions'
).
append
(
adismiss
.
data
(
'id'
,
alarm
.
id
)).
append
(
asnooze
.
data
(
'id'
,
alarm
.
id
));
$
(
'<div>'
).
addClass
(
'alarm-item'
).
html
(
html
).
append
(
actions
).
appendTo
(
this
.
alarm_dialog
);
}
var
buttons
=
{};
buttons
[
rcmail
.
gettext
(
'dismissall'
,
'calendar'
)]
=
function
()
{
// submit dismissed event_ids to server
me
.
dismiss_alarm
(
me
.
alarm_ids
.
join
(
','
),
0
);
$
(
this
).
dialog
(
'close'
);
};
this
.
alarm_dialog
.
appendTo
(
document
.
body
).
dialog
({
modal
:
false
,
resizable
:
true
,
closeOnEscape
:
false
,
dialogClass
:
'alarm'
,
title
:
rcmail
.
gettext
(
'alarmtitle'
,
'calendar'
),
buttons
:
buttons
,
close
:
function
()
{
$
(
'#alarm-snooze-dropdown'
).
hide
();
$
(
this
).
dialog
(
'destroy'
).
remove
();
me
.
alarm_dialog
=
null
;
me
.
alarm_ids
=
null
;
},
drag
:
function
(
event
,
ui
)
{
$
(
'#alarm-snooze-dropdown'
).
hide
();
}
});
this
.
alarm_ids
=
event_ids
;
};
// show a drop-down menu with a selection of snooze times
this
.
snooze_dropdown
=
function
(
link
)
{
if
(
!
this
.
snooze_popup
)
{
this
.
snooze_popup
=
$
(
'#alarm-snooze-dropdown'
);
$
(
'#alarm-snooze-dropdown a'
).
click
(
function
(
e
){
var
time
=
String
(
this
.
href
).
replace
(
/.+#/
,
''
);
me
.
dismiss_alarm
(
$
(
'#alarm-snooze-dropdown'
).
data
(
'id'
),
time
);
return
false
;
});
}
// hide visible popup
if
(
this
.
snooze_popup
.
is
(
':visible'
)
&&
this
.
snooze_popup
.
data
(
'id'
)
==
link
.
data
(
'id'
))
{
this
.
snooze_popup
.
hide
();
this
.
dismiss_link
=
null
;
}
else
{
// open popup below the clicked link
var
pos
=
link
.
offset
();
pos
.
top
+=
link
.
height
()
+
2
;
this
.
snooze_popup
.
data
(
'id'
,
link
.
data
(
'id'
)).
css
({
top
:
Math
.
floor
(
pos
.
top
)
+
'px'
,
left
:
Math
.
floor
(
pos
.
left
)
+
'px'
}).
show
();
this
.
dismiss_link
=
link
;
}
};
// dismiss or snooze alarms for the given event
this
.
dismiss_alarm
=
function
(
id
,
snooze
)
{
$
(
'#alarm-snooze-dropdown'
).
hide
();
rcmail
.
http_post
(
'plugin.event'
,
{
action
:
'dismiss'
,
e
:
{
id
:
id
,
snooze
:
snooze
}
});
// remove dismissed alarm from list
if
(
this
.
dismiss_link
)
{
this
.
dismiss_link
.
closest
(
'div.alarm-item'
).
hide
();
var
new_ids
=
jQuery
.
grep
(
this
.
alarm_ids
,
function
(
v
){
return
v
!=
id
;
});
if
(
new_ids
.
length
)
this
.
alarm_ids
=
new_ids
;
else
this
.
alarm_dialog
.
dialog
(
'close'
);
}
this
.
dismiss_link
=
null
;
};
// create list of event sources AKA calendars
this
.
calendars
=
{};
var
li
,
cal
,
event_sources
=
[];
for
(
var
id
in
rcmail
.
env
.
calendars
)
{
cal
=
rcmail
.
env
.
calendars
[
id
];
this
.
calendars
[
id
]
=
$
.
extend
({
url
:
"./?_task=calendar&_action=plugin.load_events&source="
+
escape
(
id
),
editable
:
!
cal
.
readonly
,
className
:
'fc-event-cal-'
+
id
,
id
:
id
},
cal
);
event_sources
.
push
(
this
.
calendars
[
id
]);
// init event handler on calendar list checkbox
if
((
li
=
rcmail
.
get_folder_li
(
id
,
'rcmlical'
)))
{
$
(
'#'
+
li
.
id
+
' input'
).
click
(
function
(
e
){
var
id
=
$
(
this
).
data
(
'id'
);
if
(
me
.
calendars
[
id
])
{
// add or remove event source on click
var
action
=
this
.
checked
?
'addEventSource'
:
'removeEventSource'
;
$
(
'#calendar'
).
fullCalendar
(
action
,
me
.
calendars
[
id
]);
}
}).
data
(
'id'
,
id
);
$
(
li
).
click
(
function
(
e
){
var
id
=
$
(
this
).
data
(
'id'
);
rcmail
.
select_folder
(
id
,
me
.
selected_calendar
,
'rcmlical'
);
me
.
selected_calendar
=
id
;
}).
data
(
'id'
,
id
);
}
if
(
!
cal
.
readonly
)
{
this
.
selected_calendar
=
id
;
rcmail
.
enable_command
(
'plugin.addevent'
,
true
);
}
}
// initalize the fullCalendar plugin
$
(
'#calendar'
).
fullCalendar
({
header
:
{
left
:
'prev,next today'
,
center
:
'title'
,
right
:
'agendaDay,agendaWeek,month'
},
aspectRatio
:
1
,
height
:
$
(
window
).
height
()
-
95
,
eventSources
:
event_sources
,
monthNames
:
settings
[
'months'
],
monthNamesShort
:
settings
[
'months_short'
],
dayNames
:
settings
[
'days'
],
dayNamesShort
:
settings
[
'days_short'
],
firstDay
:
settings
[
'first_day'
],
firstHour
:
settings
[
'first_hour'
],
slotMinutes
:
60
/
settings
[
'timeslots'
],
timeFormat
:
settings
[
'time_format'
],
axisFormat
:
settings
[
'time_format'
],
columnFormat
:
{
month
:
'ddd'
,
// Mon
week
:
'ddd '
+
settings
[
'date_short'
],
// Mon 9/7
day
:
'dddd '
+
settings
[
'date_short'
]
// Monday 9/7
},
defaultView
:
settings
[
'default_view'
],
allDayText
:
rcmail
.
gettext
(
'all-day'
,
'calendar'
),
buttonText
:
{
today
:
settings
[
'today'
],
day
:
rcmail
.
gettext
(
'day'
,
'calendar'
),
week
:
rcmail
.
gettext
(
'week'
,
'calendar'
),
month
:
rcmail
.
gettext
(
'month'
,
'calendar'
)
},
selectable
:
true
,
selectHelper
:
true
,
loading
:
function
(
isLoading
)
{
this
.
_rc_loading
=
rcmail
.
set_busy
(
isLoading
,
'loading'
,
this
.
_rc_loading
);
},
// event rendering
eventRender
:
function
(
event
,
element
,
view
)
{
if
(
view
.
name
!=
"month"
)
{
if
(
event
.
categories
)
{
if
(
!
event
.
allDay
)
element
.
find
(
'span.fc-event-title'
).
after
(
'<span class="fc-event-categories">'
+
event
.
categories
+
'</span>'
);
}
if
(
event
.
location
)
{
element
.
find
(
'span.fc-event-title'
).
after
(
'<span class="fc-event-location">@'
+
event
.
location
+
'</span>'
);
}
if
(
event
.
description
)
{
if
(
!
event
.
allDay
){
element
.
find
(
'span.fc-event-title'
).
after
(
'<span class="fc-event-description">'
+
event
.
description
+
'</span>'
);
}
}
}
},
// callback for date range selection
select
:
function
(
start
,
end
,
allDay
,
e
,
view
)
{
var
range_select
=
(
!
allDay
||
start
.
getDate
()
!=
end
.
getDate
())
if
(
dialog_check
(
e
)
&&
range_select
)
event_edit_dialog
(
'new'
,
{
start
:
start
,
end
:
end
,
allDay
:
allDay
,
calendar
:
me
.
selected_calendar
});
if
(
range_select
||
ignore_click
)
view
.
calendar
.
unselect
();
},
// callback for clicks in all-day box
dayClick
:
function
(
date
,
allDay
,
e
,
view
)
{
var
now
=
new
Date
().
getTime
();
if
(
now
-
day_clicked_ts
<
400
&&
day_clicked
==
date
.
getTime
())
// emulate double-click on day
return
event_edit_dialog
(
'new'
,
{
start
:
date
,
end
:
date
,
allDay
:
allDay
,
calendar
:
me
.
selected_calendar
});
if
(
!
ignore_click
)
{
view
.
calendar
.
gotoDate
(
date
);
fullcalendar_update
();
if
(
day_clicked
&&
new
Date
(
day_clicked
).
getMonth
()
!=
date
.
getMonth
())
view
.
calendar
.
select
(
date
,
date
,
allDay
);
}
day_clicked
=
date
.
getTime
();
day_clicked_ts
=
now
;
},
// callback when a specific event is clicked
eventClick
:
function
(
event
)
{
event_show_dialog
(
event
);
},
// callback when an event was dragged and finally dropped
eventDrop
:
function
(
event
,
dayDelta
,
minuteDelta
,
allDay
,
revertFunc
)
{
if
(
event
.
end
==
null
)
{
event
.
end
=
event
.
start
;
}
// send move request to server
var
data
=
{
id
:
event
.
id
,
start
:
event
.
start
.
getTime
()
/
1000
,
end
:
event
.
end
.
getTime
()
/
1000
,
allday
:
allDay
?
1
:
0
};
rcmail
.
http_post
(
'plugin.event'
,
{
action
:
'move'
,
e
:
data
});
},
// callback for event resizing
eventResize
:
function
(
event
,
delta
)
{
// send resize request to server
var
data
=
{
id
:
event
.
id
,
start
:
event
.
start
.
getTime
()
/
1000
,
end
:
event
.
end
.
getTime
()
/
1000
,
};
rcmail
.
http_post
(
'plugin.event'
,
{
action
:
'resize'
,
e
:
data
});
}
});
// event handler for clicks on calendar week cell of the datepicker widget
var
init_week_events
=
function
(){
$
(
'#datepicker table.ui-datepicker-calendar td.ui-datepicker-week-col'
).
click
(
function
(
e
){
var
base_date
=
$
(
"#datepicker"
).
datepicker
(
'getDate'
);
var
day_off
=
base_date
.
getDay
()
-
1
;
if
(
day_off
<
0
)
day_off
=
6
;
var
base_kw
=
$
.
datepicker
.
iso8601Week
(
base_date
);
var
kw
=
parseInt
(
$
(
this
).
html
());
var
diff
=
(
kw
-
base_kw
)
*
7
*
86400000
;
// select monday of the chosen calendar week
var
date
=
new
Date
(
base_date
.
getTime
()
-
day_off
*
86400000
+
diff
);
$
(
'#calendar'
).
fullCalendar
(
'gotoDate'
,
date
).
fullCalendar
(
'setDate'
,
date
).
fullCalendar
(
'changeView'
,
'agendaWeek'
);
$
(
"#datepicker"
).
datepicker
(
'setDate'
,
date
);
window
.
setTimeout
(
init_week_events
,
10
);
}).
css
(
'cursor'
,
'pointer'
);
};
// initialize small calendar widget using jQuery UI datepicker
$
(
'#datepicker'
).
datepicker
(
$
.
extend
(
this
.
datepicker_settings
,
{
inline
:
true
,
showWeek
:
true
,
changeMonth
:
false
,
// maybe enable?
changeYear
:
false
,
// maybe enable?
onSelect
:
function
(
dateText
,
inst
)
{
ignore_click
=
true
;
var
d
=
$
(
"#datepicker"
).
datepicker
(
'getDate'
);
//parse_datetime('0:0', dateText);
$
(
'#calendar'
).
fullCalendar
(
'gotoDate'
,
d
).
fullCalendar
(
'select'
,
d
,
d
,
true
);
window
.
setTimeout
(
init_week_events
,
10
);
},
onChangeMonthYear
:
function
(
year
,
month
,
inst
)
{
window
.
setTimeout
(
init_week_events
,
10
);
var
d
=
$
(
"#datepicker"
).
datepicker
(
'getDate'
);
d
.
setYear
(
year
);
d
.
setMonth
(
month
-
1
);
$
(
"#datepicker"
).
data
(
'year'
,
year
).
data
(
'month'
,
month
);
//$('#calendar').fullCalendar('gotoDate', d).fullCalendar('setDate', d);
},
}));
window
.
setTimeout
(
init_week_events
,
10
);
// react on fullcalendar buttons
var
fullcalendar_update
=
function
()
{
var
d
=
$
(
'#calendar'
).
fullCalendar
(
'getDate'
);
$
(
"#datepicker"
).
datepicker
(
'setDate'
,
d
);
window
.
setTimeout
(
init_week_events
,
10
);
};
$
(
"#calendar .fc-button-prev"
).
click
(
fullcalendar_update
);
$
(
"#calendar .fc-button-next"
).
click
(
fullcalendar_update
);
$
(
"#calendar .fc-button-today"
).
click
(
fullcalendar_update
);
// hide event dialog when clicking somewhere into document
$
(
document
).
bind
(
'mousedown'
,
dialog_check
);
}
// end rcube_calendar class
// configure toobar buttons
rcmail
.
register_command
(
'plugin.addevent'
,
function
(){
cal
.
add_event
();
},
true
);
// export events
rcmail
.
register_command
(
'plugin.export'
,
function
(){
rcmail
.
goto_url
(
'plugin.export_events'
,
{
source
:
cal
.
selected_calendar
});
},
true
);
rcmail
.
enable_command
(
'plugin.export'
,
true
);
// register callback commands
rcmail
.
addEventListener
(
'plugin.display_alarms'
,
function
(
alarms
){
cal
.
display_alarms
(
alarms
);
});
// reload calendar
rcmail
.
addEventListener
(
'plugin.reload_calendar'
,
function
()
{
$
(
'#calendar'
).
fullCalendar
(
'refetchEvents'
);
});
var
formattime
=
function
(
hour
,
minutes
)
{
return
((
hour
<
10
)
?
"0"
:
""
)
+
hour
+
((
minutes
<
10
)
?
":0"
:
":"
)
+
minutes
;
};
// if start date is changed, shift end date according to initial duration
var
shift_enddate
=
function
(
dateText
)
{
var
newstart
=
cal
.
parse_datetime
(
'0'
,
dateText
);
var
newend
=
new
Date
(
newstart
.
getTime
()
+
$
(
'#edit-startdate'
).
data
(
'duration'
)
*
1000
);
$
(
'#edit-enddate'
).
val
(
$
.
fullCalendar
.
formatDate
(
newend
,
cal
.
settings
[
'date_format'
]));
};
// let's go
var
cal
=
new
rcube_calendar
(
rcmail
.
env
.
calendar_settings
);
$
(
window
).
resize
(
function
()
{
$
(
'#calendar'
).
fullCalendar
(
'option'
,
'height'
,
$
(
window
).
height
()
-
95
);
}).
resize
();
// show toolbar
$
(
'#toolbar'
).
show
();
// init event dialog
$
(
'#eventtabs'
).
tabs
();
$
(
'#edit-enddate, input.edit-alarm-date'
).
datepicker
(
cal
.
datepicker_settings
);
$
(
'#edit-startdate'
).
datepicker
(
cal
.
datepicker_settings
).
datepicker
(
'option'
,
'onSelect'
,
shift_enddate
).
change
(
function
(){
shift_enddate
(
this
.
value
);
});
$
(
'#edit-allday'
).
click
(
function
(){
$
(
'#edit-starttime, #edit-endtime'
)[(
this
.
checked
?
'hide'
:
'show'
)]();
});
// configure drop-down menu on time input fields based on jquery UI autocomplete
$
(
'#edit-starttime, #edit-endtime, input.edit-alarm-time'
)
.
attr
(
'autocomplete'
,
"off"
)
.
autocomplete
({
delay
:
100
,
minLength
:
1
,
source
:
function
(
p
,
callback
)
{
/* Time completions */
var
result
=
[];
var
now
=
new
Date
();
var
full
=
p
.
term
-
1
>
0
||
p
.
term
.
length
>
1
;
var
hours
=
full
?
p
.
term
-
0
:
now
.
getHours
();
var
step
=
15
;
var
minutes
=
hours
*
60
+
(
full
?
0
:
now
.
getMinutes
());
var
min
=
Math
.
ceil
(
minutes
/
step
)
*
step
%
60
;
var
hour
=
Math
.
floor
(
Math
.
ceil
(
minutes
/
step
)
*
step
/
60
);
// list hours from 0:00 till now
for
(
var
h
=
0
;
h
<
hours
;
h
++
)
result
.
push
(
formattime
(
h
,
0
));
// list 15min steps for the next two hours
for
(;
h
<
hour
+
2
;
h
++
)
{
while
(
min
<
60
)
{
result
.
push
(
formattime
(
h
,
min
));
min
+=
step
;
}
min
=
0
;
}
// list the remaining hours till 23:00
while
(
h
<
24
)
result
.
push
(
formattime
((
h
++
),
0
));
return
callback
(
result
);
},
open
:
function
(
event
,
ui
)
{
// scroll to current time
var
widget
=
$
(
this
).
autocomplete
(
'widget'
);
var
menu
=
$
(
this
).
data
(
'autocomplete'
).
menu
;
var
val
=
$
(
this
).
val
();
var
li
,
html
,
offset
=
0
;
widget
.
children
().
each
(
function
(){
li
=
$
(
this
);
html
=
li
.
children
().
first
().
html
();
if
(
html
<
val
)
offset
+=
li
.
height
();
if
(
html
==
val
)
menu
.
activate
(
$
.
Event
({
type
:
'mouseenter'
}),
li
);
});
widget
.
scrollTop
(
offset
-
1
);
}
})
.
click
(
function
()
{
// show drop-down upon clicks
$
(
this
).
autocomplete
(
'search'
,
$
(
this
).
val
()
?
$
(
this
).
val
().
replace
(
/\D.*/
,
""
)
:
" "
);
});
// register events on alarm fields
$
(
'select.edit-alarm-type'
).
change
(
function
(){
$
(
this
).
parent
().
find
(
'span.edit-alarm-values'
)[(
this
.
selectedIndex
>
0
?
'show'
:
'hide'
)]();
});
$
(
'select.edit-alarm-offset'
).
change
(
function
(){
var
mode
=
$
(
this
).
val
()
==
'@'
?
'show'
:
'hide'
;
$
(
this
).
parent
().
find
(
'.edit-alarm-date, .edit-alarm-time'
)[
mode
]();
$
(
this
).
parent
().
find
(
'.edit-alarm-value'
).
prop
(
'disabled'
,
mode
==
'show'
);
});
// toggle recurrence frequency forms
$
(
'#edit-recurrence-frequency'
).
change
(
function
(
e
){
var
freq
=
$
(
this
).
val
().
toLowerCase
();
$
(
'.recurrence-form'
).
hide
();
if
(
freq
)
$
(
'#recurrence-form-'
+
freq
+
', #recurrence-form-until'
).
show
();
});
$
(
'#edit-recurrence-enddate'
).
datepicker
(
cal
.
datepicker_settings
).
click
(
function
(){
$
(
"#edit-recurrence-repeat-until"
).
prop
(
'checked'
,
true
)
});
// avoid unselecting all weekdays, monthdays and months
$
(
'input.edit-recurrence-weekly-byday, input.edit-recurrence-monthly-bymonthday, input.edit-recurrence-yearly-bymonth'
).
click
(
function
(){
if
(
!
$
(
'input.'
+
this
.
className
+
':checked'
).
length
)
this
.
checked
=
true
;
});
// initialize sidebar toggle
$
(
'#sidebartoggle'
).
click
(
function
()
{
var
width
=
$
(
this
).
data
(
'sidebarwidth'
);
var
offset
=
$
(
this
).
data
(
'offset'
);
var
$sidebar
=
$
(
'#sidebar'
),
time
=
250
;
if
(
$sidebar
.
is
(
':visible'
))
{
$sidebar
.
animate
({
left
:
'-'
+
(
width
+
10
)
+
'px'
},
time
,
function
(){
$
(
'#sidebar'
).
hide
();
});
$
(
this
).
animate
({
left
:
'6px'
},
time
,
function
(){
$
(
'#sidebartoggle'
).
addClass
(
'sidebarclosed'
)
});
$
(
'#calendar'
).
animate
({
left
:
'20px'
},
time
,
function
(){
$
(
this
).
fullCalendar
(
'render'
);
});
}
else
{
$sidebar
.
show
().
animate
({
left
:
'10px'
},
time
);
$
(
this
).
animate
({
left
:
offset
+
'px'
},
time
,
function
(){
$
(
'#sidebartoggle'
).
removeClass
(
'sidebarclosed'
);
});
$
(
'#calendar'
).
animate
({
left
:
(
width
+
20
)
+
'px'
},
time
,
function
(){
$
(
this
).
fullCalendar
(
'render'
);
});
}
})
.
data
(
'offset'
,
$
(
'#sidebartoggle'
).
position
().
left
)
.
data
(
'sidebarwidth'
,
$
(
'#sidebar'
).
width
()
+
$
(
'#sidebar'
).
position
().
left
);
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jun 12, 3:34 AM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
914668
Default Alt Text
calendar.js (36 KB)
Attached To
Mode
R14 roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline
Log In to Comment