fullcalendar.io-rails 2.9.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/fullcalendar.io/rails/version.rb +1 -1
- data/spec/features/assets_spec.rb +2 -2
- data/vendor/assets/javascripts/fullcalendar.js +897 -668
- data/vendor/assets/javascripts/fullcalendar/gcal.js +3 -3
- data/vendor/assets/javascripts/fullcalendar/locale-all.js +5 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ar-ma.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ar-sa.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ar-tn.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ar.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/bg.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ca.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/cs.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/da.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/de-at.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/de.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/el.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/en-au.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/en-ca.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/en-gb.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/en-ie.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/en-nz.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/es-do.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/es.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/eu.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/fa.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/fi.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/fr-ca.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/fr-ch.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/fr.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/gl.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/he.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/hi.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/hr.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/hu.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/id.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/is.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/it.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ja.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ko.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/lb.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/lt.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/lv.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/mk.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ms-my.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ms.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/nb.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/nl.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/nn.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/pl.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/pt-br.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/pt.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ro.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ru.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/sk.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/sl.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/sr-cyrl.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/sr.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/sv.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/th.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/tr.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/uk.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/vi.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/zh-cn.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/zh-tw.js +1 -0
- data/vendor/assets/stylesheets/fullcalendar.css +172 -36
- data/vendor/assets/stylesheets/fullcalendar.print.css +3 -3
- metadata +132 -58
- data/vendor/assets/javascripts/fullcalendar/lang-all.js +0 -4
- data/vendor/assets/javascripts/fullcalendar/lang/ar-ma.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ar-sa.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ar-tn.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ar.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/bg.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ca.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/cs.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/da.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/de-at.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/de.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/el.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/en-au.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/en-ca.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/en-gb.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/en-ie.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/en-nz.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/es.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/eu.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/fa.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/fi.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/fr-ca.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/fr-ch.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/fr.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/gl.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/he.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/hi.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/hr.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/hu.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/id.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/is.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/it.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ja.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ko.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/lb.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/lt.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/lv.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/nb.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/nl.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/nn.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/pl.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/pt-br.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/pt.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ro.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/ru.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/sk.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/sl.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/sr-cyrl.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/sr.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/sv.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/th.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/tr.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/uk.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/vi.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/zh-cn.js +0 -1
- data/vendor/assets/javascripts/fullcalendar/lang/zh-tw.js +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 080eb65bbd868198fdad6cba05d63a26cd761794
|
4
|
+
data.tar.gz: a78008ae83226e149ba731c61741b0dddf4ff447
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e187a13847636e4a8ab145ecb702adb0688aa6ff71d57cf4bc86040c9bd0ca12c043b98ac8e265743bf3ac94ecf75b734b4bb38fc69c0513577f9dba3f298c1f
|
7
|
+
data.tar.gz: 3d9bff653feea5d47b21c5937d534cf8955df67109f76abef3336928534a049b6aeb8b3686a7a62e6a3d4c9d1235a7298510fa71bc9b2da7c8c20fde9a1d2e9c
|
data/README.md
CHANGED
@@ -28,10 +28,10 @@ And in your application.js:
|
|
28
28
|
//= require moment
|
29
29
|
//= require fullcalendar
|
30
30
|
|
31
|
-
Language files, gcal.js and
|
31
|
+
Language files, gcal.js and locale-all.js are located under "fullcalendar" subdirectory.
|
32
32
|
|
33
33
|
//= require fullcalendar/gcal
|
34
|
-
//= require fullcalendar/
|
34
|
+
//= require fullcalendar/locale/pl
|
35
35
|
|
36
36
|
## Usage
|
37
37
|
|
@@ -11,8 +11,8 @@ feature 'Assets integration' do
|
|
11
11
|
expect(page.status_code).to be 200
|
12
12
|
end
|
13
13
|
|
14
|
-
it 'provides fullcalendar/
|
15
|
-
visit '/assets/fullcalendar/
|
14
|
+
it 'provides fullcalendar/locale/pl.js on the asset pipeline' do
|
15
|
+
visit '/assets/fullcalendar/locale/pl.js'
|
16
16
|
expect(page.status_code).to be 200
|
17
17
|
end
|
18
18
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/*!
|
2
|
-
*
|
3
|
-
* Docs & License:
|
4
|
-
* (c)
|
2
|
+
* FullCalendar v3.0.0
|
3
|
+
* Docs & License: http://fullcalendar.io/
|
4
|
+
* (c) 2016 Adam Shaw
|
5
5
|
*/
|
6
6
|
|
7
7
|
(function(factory) {
|
@@ -19,8 +19,8 @@
|
|
19
19
|
;;
|
20
20
|
|
21
21
|
var FC = $.fullCalendar = {
|
22
|
-
version: "
|
23
|
-
internalApiVersion:
|
22
|
+
version: "3.0.0",
|
23
|
+
internalApiVersion: 6
|
24
24
|
};
|
25
25
|
var fcViews = FC.views = {};
|
26
26
|
|
@@ -71,56 +71,6 @@ function mergeOptions(optionObjs) {
|
|
71
71
|
return mergeProps(optionObjs, complexOptions);
|
72
72
|
}
|
73
73
|
|
74
|
-
|
75
|
-
// Given options specified for the calendar's constructor, massages any legacy options into a non-legacy form.
|
76
|
-
// Converts View-Option-Hashes into the View-Specific-Options format.
|
77
|
-
function massageOverrides(input) {
|
78
|
-
var overrides = { views: input.views || {} }; // the output. ensure a `views` hash
|
79
|
-
var subObj;
|
80
|
-
|
81
|
-
// iterate through all option override properties (except `views`)
|
82
|
-
$.each(input, function(name, val) {
|
83
|
-
if (name != 'views') {
|
84
|
-
|
85
|
-
// could the value be a legacy View-Option-Hash?
|
86
|
-
if (
|
87
|
-
$.isPlainObject(val) &&
|
88
|
-
!/(time|duration|interval)$/i.test(name) && // exclude duration options. might be given as objects
|
89
|
-
$.inArray(name, complexOptions) == -1 // complex options aren't allowed to be View-Option-Hashes
|
90
|
-
) {
|
91
|
-
subObj = null;
|
92
|
-
|
93
|
-
// iterate through the properties of this possible View-Option-Hash value
|
94
|
-
$.each(val, function(subName, subVal) {
|
95
|
-
|
96
|
-
// is the property targeting a view?
|
97
|
-
if (/^(month|week|day|default|basic(Week|Day)?|agenda(Week|Day)?)$/.test(subName)) {
|
98
|
-
if (!overrides.views[subName]) { // ensure the view-target entry exists
|
99
|
-
overrides.views[subName] = {};
|
100
|
-
}
|
101
|
-
overrides.views[subName][name] = subVal; // record the value in the `views` object
|
102
|
-
}
|
103
|
-
else { // a non-View-Option-Hash property
|
104
|
-
if (!subObj) {
|
105
|
-
subObj = {};
|
106
|
-
}
|
107
|
-
subObj[subName] = subVal; // accumulate these unrelated values for later
|
108
|
-
}
|
109
|
-
});
|
110
|
-
|
111
|
-
if (subObj) { // non-View-Option-Hash properties? transfer them as-is
|
112
|
-
overrides[name] = subObj;
|
113
|
-
}
|
114
|
-
}
|
115
|
-
else {
|
116
|
-
overrides[name] = val; // transfer normal options as-is
|
117
|
-
}
|
118
|
-
}
|
119
|
-
});
|
120
|
-
|
121
|
-
return overrides;
|
122
|
-
}
|
123
|
-
|
124
74
|
;;
|
125
75
|
|
126
76
|
// exports
|
@@ -247,7 +197,7 @@ function undistributeHeight(els) {
|
|
247
197
|
function matchCellWidths(els) {
|
248
198
|
var maxInnerWidth = 0;
|
249
199
|
|
250
|
-
els.find('>
|
200
|
+
els.find('> *').each(function(i, innerEl) {
|
251
201
|
var innerWidth = $(innerEl).outerWidth();
|
252
202
|
if (innerWidth > maxInnerWidth) {
|
253
203
|
maxInnerWidth = innerWidth;
|
@@ -628,7 +578,8 @@ function flexibleCompare(a, b) {
|
|
628
578
|
----------------------------------------------------------------------------------------------------------------------*/
|
629
579
|
|
630
580
|
|
631
|
-
// Computes the intersection of the two ranges.
|
581
|
+
// Computes the intersection of the two ranges. Will return fresh date clones in a range.
|
582
|
+
// Returns undefined if no intersection.
|
632
583
|
// Expects all dates to be normalized to the same timezone beforehand.
|
633
584
|
// TODO: move to date section?
|
634
585
|
function intersectRanges(subjectRange, constraintRange) {
|
@@ -908,22 +859,6 @@ function copyOwnProps(src, dest) {
|
|
908
859
|
}
|
909
860
|
|
910
861
|
|
911
|
-
// Copies over certain methods with the same names as Object.prototype methods. Overcomes an IE<=8 bug:
|
912
|
-
// https://developer.mozilla.org/en-US/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
|
913
|
-
function copyNativeMethods(src, dest) {
|
914
|
-
var names = [ 'constructor', 'toString', 'valueOf' ];
|
915
|
-
var i, name;
|
916
|
-
|
917
|
-
for (i = 0; i < names.length; i++) {
|
918
|
-
name = names[i];
|
919
|
-
|
920
|
-
if (src[name] !== Object.prototype[name]) {
|
921
|
-
dest[name] = src[name];
|
922
|
-
}
|
923
|
-
}
|
924
|
-
}
|
925
|
-
|
926
|
-
|
927
862
|
function hasOwnProp(obj, name) {
|
928
863
|
return hasOwnPropMethod.call(obj, name);
|
929
864
|
}
|
@@ -989,6 +924,21 @@ function cssToStr(cssProps) {
|
|
989
924
|
}
|
990
925
|
|
991
926
|
|
927
|
+
// Given an object hash of HTML attribute names to values,
|
928
|
+
// generates a string that can be injected between < > in HTML
|
929
|
+
function attrsToStr(attrs) {
|
930
|
+
var parts = [];
|
931
|
+
|
932
|
+
$.each(attrs, function(name, val) {
|
933
|
+
if (val != null) {
|
934
|
+
parts.push(name + '="' + htmlEscape(val) + '"');
|
935
|
+
}
|
936
|
+
});
|
937
|
+
|
938
|
+
return parts.join(' ');
|
939
|
+
}
|
940
|
+
|
941
|
+
|
992
942
|
function capitaliseFirstLetter(str) {
|
993
943
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
994
944
|
}
|
@@ -1070,14 +1020,24 @@ function syncThen(promise, thenFunc) {
|
|
1070
1020
|
|
1071
1021
|
;;
|
1072
1022
|
|
1023
|
+
/*
|
1024
|
+
GENERAL NOTE on moments throughout the *entire rest* of the codebase:
|
1025
|
+
All moments are assumed to be ambiguously-zoned unless otherwise noted,
|
1026
|
+
with the NOTABLE EXCEOPTION of start/end dates that live on *Event Objects*.
|
1027
|
+
Ambiguously-TIMED moments are assumed to be ambiguously-zoned by nature.
|
1028
|
+
*/
|
1029
|
+
|
1073
1030
|
var ambigDateOfMonthRegex = /^\s*\d{4}-\d\d$/;
|
1074
1031
|
var ambigTimeOrZoneRegex =
|
1075
1032
|
/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/;
|
1076
1033
|
var newMomentProto = moment.fn; // where we will attach our new methods
|
1077
1034
|
var oldMomentProto = $.extend({}, newMomentProto); // copy of original moment methods
|
1078
|
-
|
1079
|
-
|
1080
|
-
var
|
1035
|
+
|
1036
|
+
// tell momentjs to transfer these properties upon clone
|
1037
|
+
var momentProperties = moment.momentProperties;
|
1038
|
+
momentProperties.push('_fullCalendar');
|
1039
|
+
momentProperties.push('_ambigTime');
|
1040
|
+
momentProperties.push('_ambigZone');
|
1081
1041
|
|
1082
1042
|
|
1083
1043
|
// Creating
|
@@ -1123,12 +1083,8 @@ function makeMoment(args, parseAsUTC, parseZone) {
|
|
1123
1083
|
var ambigMatch;
|
1124
1084
|
var mom;
|
1125
1085
|
|
1126
|
-
if (moment.isMoment(input)) {
|
1127
|
-
mom = moment.apply(null, args);
|
1128
|
-
transferAmbigs(input, mom); // the ambig flags weren't transfered with the clone
|
1129
|
-
}
|
1130
|
-
else if (isNativeDate(input) || input === undefined) {
|
1131
|
-
mom = moment.apply(null, args); // will be local
|
1086
|
+
if (moment.isMoment(input) || isNativeDate(input) || input === undefined) {
|
1087
|
+
mom = moment.apply(null, args);
|
1132
1088
|
}
|
1133
1089
|
else { // "parsing" is required
|
1134
1090
|
isAmbigTime = false;
|
@@ -1169,12 +1125,7 @@ function makeMoment(args, parseAsUTC, parseZone) {
|
|
1169
1125
|
mom._ambigZone = true;
|
1170
1126
|
}
|
1171
1127
|
else if (isSingleString) {
|
1172
|
-
|
1173
|
-
mom.utcOffset(input); // if not a valid zone, will assign UTC
|
1174
|
-
}
|
1175
|
-
else {
|
1176
|
-
mom.zone(input); // for moment-pre-2.9
|
1177
|
-
}
|
1128
|
+
mom.utcOffset(input); // if not a valid zone, will assign UTC
|
1178
1129
|
}
|
1179
1130
|
}
|
1180
1131
|
}
|
@@ -1185,21 +1136,6 @@ function makeMoment(args, parseAsUTC, parseZone) {
|
|
1185
1136
|
}
|
1186
1137
|
|
1187
1138
|
|
1188
|
-
// A clone method that works with the flags related to our enhanced functionality.
|
1189
|
-
// In the future, use moment.momentProperties
|
1190
|
-
newMomentProto.clone = function() {
|
1191
|
-
var mom = oldMomentProto.clone.apply(this, arguments);
|
1192
|
-
|
1193
|
-
// these flags weren't transfered with the clone
|
1194
|
-
transferAmbigs(this, mom);
|
1195
|
-
if (this._fullCalendar) {
|
1196
|
-
mom._fullCalendar = true;
|
1197
|
-
}
|
1198
|
-
|
1199
|
-
return mom;
|
1200
|
-
};
|
1201
|
-
|
1202
|
-
|
1203
1139
|
// Week Number
|
1204
1140
|
// -------------------------------------------------------------------------------------------------
|
1205
1141
|
|
@@ -1207,8 +1143,7 @@ newMomentProto.clone = function() {
|
|
1207
1143
|
// Returns the week number, considering the locale's custom week number calcuation
|
1208
1144
|
// `weeks` is an alias for `week`
|
1209
1145
|
newMomentProto.week = newMomentProto.weeks = function(input) {
|
1210
|
-
var weekCalc =
|
1211
|
-
._fullCalendar_weekCalc;
|
1146
|
+
var weekCalc = this._locale._fullCalendar_weekCalc;
|
1212
1147
|
|
1213
1148
|
if (input == null && typeof weekCalc === 'function') { // custom function only works for getter
|
1214
1149
|
return weekCalc(this);
|
@@ -1275,19 +1210,21 @@ newMomentProto.time = function(time) {
|
|
1275
1210
|
// but preserving its YMD. A moment with a stripped time will display no time
|
1276
1211
|
// nor timezone offset when .format() is called.
|
1277
1212
|
newMomentProto.stripTime = function() {
|
1278
|
-
var a;
|
1279
1213
|
|
1280
1214
|
if (!this._ambigTime) {
|
1281
1215
|
|
1282
|
-
//
|
1283
|
-
a = this.toArray(); // array of y/m/d/h/m/s/ms
|
1216
|
+
this.utc(true); // keepLocalTime=true (for keeping *date* value)
|
1284
1217
|
|
1285
|
-
//
|
1286
|
-
this.
|
1287
|
-
|
1218
|
+
// set time to zero
|
1219
|
+
this.set({
|
1220
|
+
hours: 0,
|
1221
|
+
minutes: 0,
|
1222
|
+
seconds: 0,
|
1223
|
+
ms: 0
|
1224
|
+
});
|
1288
1225
|
|
1289
1226
|
// Mark the time as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
|
1290
|
-
// which clears all ambig flags.
|
1227
|
+
// which clears all ambig flags.
|
1291
1228
|
this._ambigTime = true;
|
1292
1229
|
this._ambigZone = true; // if ambiguous time, also ambiguous timezone offset
|
1293
1230
|
}
|
@@ -1307,24 +1244,20 @@ newMomentProto.hasTime = function() {
|
|
1307
1244
|
// Converts the moment to UTC, stripping out its timezone offset, but preserving its
|
1308
1245
|
// YMD and time-of-day. A moment with a stripped timezone offset will display no
|
1309
1246
|
// timezone offset when .format() is called.
|
1310
|
-
// TODO: look into Moment's keepLocalTime functionality
|
1311
1247
|
newMomentProto.stripZone = function() {
|
1312
|
-
var
|
1248
|
+
var wasAmbigTime;
|
1313
1249
|
|
1314
1250
|
if (!this._ambigZone) {
|
1315
1251
|
|
1316
|
-
// get the values before any conversion happens
|
1317
|
-
a = this.toArray(); // array of y/m/d/h/m/s/ms
|
1318
1252
|
wasAmbigTime = this._ambigTime;
|
1319
1253
|
|
1320
|
-
this.utc(); //
|
1321
|
-
setUTCValues(this, a); // will set the year/month/date/hours/minutes/seconds/ms
|
1254
|
+
this.utc(true); // keepLocalTime=true (for keeping date and time values)
|
1322
1255
|
|
1323
1256
|
// the above call to .utc()/.utcOffset() unfortunately might clear the ambig flags, so restore
|
1324
1257
|
this._ambigTime = wasAmbigTime || false;
|
1325
1258
|
|
1326
1259
|
// Mark the zone as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
|
1327
|
-
// which clears the ambig flags.
|
1260
|
+
// which clears the ambig flags.
|
1328
1261
|
this._ambigZone = true;
|
1329
1262
|
}
|
1330
1263
|
|
@@ -1337,32 +1270,26 @@ newMomentProto.hasZone = function() {
|
|
1337
1270
|
};
|
1338
1271
|
|
1339
1272
|
|
1340
|
-
//
|
1341
|
-
newMomentProto.local = function() {
|
1342
|
-
var a = this.toArray(); // year,month,date,hours,minutes,seconds,ms as an array
|
1343
|
-
var wasAmbigZone = this._ambigZone;
|
1273
|
+
// implicitly marks a zone
|
1274
|
+
newMomentProto.local = function(keepLocalTime) {
|
1344
1275
|
|
1345
|
-
|
1276
|
+
// for when converting from ambiguously-zoned to local,
|
1277
|
+
// keep the time values when converting from UTC -> local
|
1278
|
+
oldMomentProto.local.call(this, this._ambigZone || keepLocalTime);
|
1346
1279
|
|
1347
1280
|
// ensure non-ambiguous
|
1348
1281
|
// this probably already happened via local() -> utcOffset(), but don't rely on Moment's internals
|
1349
1282
|
this._ambigTime = false;
|
1350
1283
|
this._ambigZone = false;
|
1351
1284
|
|
1352
|
-
if (wasAmbigZone) {
|
1353
|
-
// If the moment was ambiguously zoned, the date fields were stored as UTC.
|
1354
|
-
// We want to preserve these, but in local time.
|
1355
|
-
// TODO: look into Moment's keepLocalTime functionality
|
1356
|
-
setLocalValues(this, a);
|
1357
|
-
}
|
1358
|
-
|
1359
1285
|
return this; // for chaining
|
1360
1286
|
};
|
1361
1287
|
|
1362
1288
|
|
1363
1289
|
// implicitly marks a zone
|
1364
|
-
newMomentProto.utc = function() {
|
1365
|
-
|
1290
|
+
newMomentProto.utc = function(keepLocalTime) {
|
1291
|
+
|
1292
|
+
oldMomentProto.utc.call(this, keepLocalTime);
|
1366
1293
|
|
1367
1294
|
// ensure non-ambiguous
|
1368
1295
|
// this probably already happened via utc() -> utcOffset(), but don't rely on Moment's internals
|
@@ -1373,28 +1300,18 @@ newMomentProto.utc = function() {
|
|
1373
1300
|
};
|
1374
1301
|
|
1375
1302
|
|
1376
|
-
//
|
1377
|
-
|
1378
|
-
$.each([
|
1379
|
-
'zone', // only in moment-pre-2.9. deprecated afterwards
|
1380
|
-
'utcOffset'
|
1381
|
-
], function(i, name) {
|
1382
|
-
if (oldMomentProto[name]) { // original method exists?
|
1383
|
-
|
1384
|
-
// this method implicitly marks a zone (will probably get called upon .utc() and .local())
|
1385
|
-
newMomentProto[name] = function(tzo) {
|
1303
|
+
// implicitly marks a zone (will probably get called upon .utc() and .local())
|
1304
|
+
newMomentProto.utcOffset = function(tzo) {
|
1386
1305
|
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
}
|
1393
|
-
|
1394
|
-
return oldMomentProto[name].apply(this, arguments);
|
1395
|
-
};
|
1306
|
+
if (tzo != null) { // setter
|
1307
|
+
// these assignments needs to happen before the original zone method is called.
|
1308
|
+
// I forget why, something to do with a browser crash.
|
1309
|
+
this._ambigTime = false;
|
1310
|
+
this._ambigZone = false;
|
1396
1311
|
}
|
1397
|
-
|
1312
|
+
|
1313
|
+
return oldMomentProto.utcOffset.apply(this, arguments);
|
1314
|
+
};
|
1398
1315
|
|
1399
1316
|
|
1400
1317
|
// Formatting
|
@@ -1423,156 +1340,6 @@ newMomentProto.toISOString = function() {
|
|
1423
1340
|
return oldMomentProto.toISOString.apply(this, arguments);
|
1424
1341
|
};
|
1425
1342
|
|
1426
|
-
|
1427
|
-
// Querying
|
1428
|
-
// -------------------------------------------------------------------------------------------------
|
1429
|
-
|
1430
|
-
// Is the moment within the specified range? `end` is exclusive.
|
1431
|
-
// FYI, this method is not a standard Moment method, so always do our enhanced logic.
|
1432
|
-
newMomentProto.isWithin = function(start, end) {
|
1433
|
-
var a = commonlyAmbiguate([ this, start, end ]);
|
1434
|
-
return a[0] >= a[1] && a[0] < a[2];
|
1435
|
-
};
|
1436
|
-
|
1437
|
-
// When isSame is called with units, timezone ambiguity is normalized before the comparison happens.
|
1438
|
-
// If no units specified, the two moments must be identically the same, with matching ambig flags.
|
1439
|
-
newMomentProto.isSame = function(input, units) {
|
1440
|
-
var a;
|
1441
|
-
|
1442
|
-
// only do custom logic if this is an enhanced moment
|
1443
|
-
if (!this._fullCalendar) {
|
1444
|
-
return oldMomentProto.isSame.apply(this, arguments);
|
1445
|
-
}
|
1446
|
-
|
1447
|
-
if (units) {
|
1448
|
-
a = commonlyAmbiguate([ this, input ], true); // normalize timezones but don't erase times
|
1449
|
-
return oldMomentProto.isSame.call(a[0], a[1], units);
|
1450
|
-
}
|
1451
|
-
else {
|
1452
|
-
input = FC.moment.parseZone(input); // normalize input
|
1453
|
-
return oldMomentProto.isSame.call(this, input) &&
|
1454
|
-
Boolean(this._ambigTime) === Boolean(input._ambigTime) &&
|
1455
|
-
Boolean(this._ambigZone) === Boolean(input._ambigZone);
|
1456
|
-
}
|
1457
|
-
};
|
1458
|
-
|
1459
|
-
// Make these query methods work with ambiguous moments
|
1460
|
-
$.each([
|
1461
|
-
'isBefore',
|
1462
|
-
'isAfter'
|
1463
|
-
], function(i, methodName) {
|
1464
|
-
newMomentProto[methodName] = function(input, units) {
|
1465
|
-
var a;
|
1466
|
-
|
1467
|
-
// only do custom logic if this is an enhanced moment
|
1468
|
-
if (!this._fullCalendar) {
|
1469
|
-
return oldMomentProto[methodName].apply(this, arguments);
|
1470
|
-
}
|
1471
|
-
|
1472
|
-
a = commonlyAmbiguate([ this, input ]);
|
1473
|
-
return oldMomentProto[methodName].call(a[0], a[1], units);
|
1474
|
-
};
|
1475
|
-
});
|
1476
|
-
|
1477
|
-
|
1478
|
-
// Misc Internals
|
1479
|
-
// -------------------------------------------------------------------------------------------------
|
1480
|
-
|
1481
|
-
// given an array of moment-like inputs, return a parallel array w/ moments similarly ambiguated.
|
1482
|
-
// for example, of one moment has ambig time, but not others, all moments will have their time stripped.
|
1483
|
-
// set `preserveTime` to `true` to keep times, but only normalize zone ambiguity.
|
1484
|
-
// returns the original moments if no modifications are necessary.
|
1485
|
-
function commonlyAmbiguate(inputs, preserveTime) {
|
1486
|
-
var anyAmbigTime = false;
|
1487
|
-
var anyAmbigZone = false;
|
1488
|
-
var len = inputs.length;
|
1489
|
-
var moms = [];
|
1490
|
-
var i, mom;
|
1491
|
-
|
1492
|
-
// parse inputs into real moments and query their ambig flags
|
1493
|
-
for (i = 0; i < len; i++) {
|
1494
|
-
mom = inputs[i];
|
1495
|
-
if (!moment.isMoment(mom)) {
|
1496
|
-
mom = FC.moment.parseZone(mom);
|
1497
|
-
}
|
1498
|
-
anyAmbigTime = anyAmbigTime || mom._ambigTime;
|
1499
|
-
anyAmbigZone = anyAmbigZone || mom._ambigZone;
|
1500
|
-
moms.push(mom);
|
1501
|
-
}
|
1502
|
-
|
1503
|
-
// strip each moment down to lowest common ambiguity
|
1504
|
-
// use clones to avoid modifying the original moments
|
1505
|
-
for (i = 0; i < len; i++) {
|
1506
|
-
mom = moms[i];
|
1507
|
-
if (!preserveTime && anyAmbigTime && !mom._ambigTime) {
|
1508
|
-
moms[i] = mom.clone().stripTime();
|
1509
|
-
}
|
1510
|
-
else if (anyAmbigZone && !mom._ambigZone) {
|
1511
|
-
moms[i] = mom.clone().stripZone();
|
1512
|
-
}
|
1513
|
-
}
|
1514
|
-
|
1515
|
-
return moms;
|
1516
|
-
}
|
1517
|
-
|
1518
|
-
// Transfers all the flags related to ambiguous time/zone from the `src` moment to the `dest` moment
|
1519
|
-
// TODO: look into moment.momentProperties for this.
|
1520
|
-
function transferAmbigs(src, dest) {
|
1521
|
-
if (src._ambigTime) {
|
1522
|
-
dest._ambigTime = true;
|
1523
|
-
}
|
1524
|
-
else if (dest._ambigTime) {
|
1525
|
-
dest._ambigTime = false;
|
1526
|
-
}
|
1527
|
-
|
1528
|
-
if (src._ambigZone) {
|
1529
|
-
dest._ambigZone = true;
|
1530
|
-
}
|
1531
|
-
else if (dest._ambigZone) {
|
1532
|
-
dest._ambigZone = false;
|
1533
|
-
}
|
1534
|
-
}
|
1535
|
-
|
1536
|
-
|
1537
|
-
// Sets the year/month/date/etc values of the moment from the given array.
|
1538
|
-
// Inefficient because it calls each individual setter.
|
1539
|
-
function setMomentValues(mom, a) {
|
1540
|
-
mom.year(a[0] || 0)
|
1541
|
-
.month(a[1] || 0)
|
1542
|
-
.date(a[2] || 0)
|
1543
|
-
.hours(a[3] || 0)
|
1544
|
-
.minutes(a[4] || 0)
|
1545
|
-
.seconds(a[5] || 0)
|
1546
|
-
.milliseconds(a[6] || 0);
|
1547
|
-
}
|
1548
|
-
|
1549
|
-
// Can we set the moment's internal date directly?
|
1550
|
-
allowValueOptimization = '_d' in moment() && 'updateOffset' in moment;
|
1551
|
-
|
1552
|
-
// Utility function. Accepts a moment and an array of the UTC year/month/date/etc values to set.
|
1553
|
-
// Assumes the given moment is already in UTC mode.
|
1554
|
-
setUTCValues = allowValueOptimization ? function(mom, a) {
|
1555
|
-
// simlate what moment's accessors do
|
1556
|
-
mom._d.setTime(Date.UTC.apply(Date, a));
|
1557
|
-
moment.updateOffset(mom, false); // keepTime=false
|
1558
|
-
} : setMomentValues;
|
1559
|
-
|
1560
|
-
// Utility function. Accepts a moment and an array of the local year/month/date/etc values to set.
|
1561
|
-
// Assumes the given moment is already in local mode.
|
1562
|
-
setLocalValues = allowValueOptimization ? function(mom, a) {
|
1563
|
-
// simlate what moment's accessors do
|
1564
|
-
mom._d.setTime(+new Date( // FYI, there is now way to apply an array of args to a constructor
|
1565
|
-
a[0] || 0,
|
1566
|
-
a[1] || 0,
|
1567
|
-
a[2] || 0,
|
1568
|
-
a[3] || 0,
|
1569
|
-
a[4] || 0,
|
1570
|
-
a[5] || 0,
|
1571
|
-
a[6] || 0
|
1572
|
-
));
|
1573
|
-
moment.updateOffset(mom, false); // keepTime=false
|
1574
|
-
} : setMomentValues;
|
1575
|
-
|
1576
1343
|
;;
|
1577
1344
|
|
1578
1345
|
// Single Date Formatting
|
@@ -1653,7 +1420,7 @@ function formatRange(date1, date2, formatStr, separator, isRTL) {
|
|
1653
1420
|
date1 = FC.moment.parseZone(date1);
|
1654
1421
|
date2 = FC.moment.parseZone(date2);
|
1655
1422
|
|
1656
|
-
localeData =
|
1423
|
+
localeData = date1.localeData();
|
1657
1424
|
|
1658
1425
|
// Expand localized format strings, like "LL" -> "MMMM D YYYY"
|
1659
1426
|
formatStr = localeData.longDateFormat(formatStr) || formatStr;
|
@@ -1858,7 +1625,6 @@ function extendClass(superClass, members) {
|
|
1858
1625
|
|
1859
1626
|
// copy each member variable/method onto the the subclass's prototype
|
1860
1627
|
copyOwnProps(members, subClass.prototype);
|
1861
|
-
copyNativeMethods(members, subClass.prototype); // hack for IE8
|
1862
1628
|
|
1863
1629
|
// copy over all class variables/methods to the subclass, such as `extend` and `mixin`
|
1864
1630
|
copyOwnProps(superClass, subClass);
|
@@ -1868,7 +1634,7 @@ function extendClass(superClass, members) {
|
|
1868
1634
|
|
1869
1635
|
|
1870
1636
|
function mixIntoClass(theClass, members) {
|
1871
|
-
copyOwnProps(members, theClass.prototype);
|
1637
|
+
copyOwnProps(members, theClass.prototype);
|
1872
1638
|
}
|
1873
1639
|
;;
|
1874
1640
|
|
@@ -2446,10 +2212,7 @@ var CoordCache = FC.CoordCache = Class.extend({
|
|
2446
2212
|
var DragListener = FC.DragListener = Class.extend(ListenerMixin, MouseIgnorerMixin, {
|
2447
2213
|
|
2448
2214
|
options: null,
|
2449
|
-
|
2450
|
-
// for IE8 bug-fighting behavior
|
2451
2215
|
subjectEl: null,
|
2452
|
-
subjectHref: null,
|
2453
2216
|
|
2454
2217
|
// coordinates of the initial mousedown
|
2455
2218
|
originX: null,
|
@@ -2640,7 +2403,6 @@ var DragListener = FC.DragListener = Class.extend(ListenerMixin, MouseIgnorerMix
|
|
2640
2403
|
|
2641
2404
|
handleDragStart: function(ev) {
|
2642
2405
|
this.trigger('dragStart', ev);
|
2643
|
-
this.initHrefHack();
|
2644
2406
|
},
|
2645
2407
|
|
2646
2408
|
|
@@ -2680,7 +2442,6 @@ var DragListener = FC.DragListener = Class.extend(ListenerMixin, MouseIgnorerMix
|
|
2680
2442
|
|
2681
2443
|
handleDragEnd: function(ev) {
|
2682
2444
|
this.trigger('dragEnd', ev);
|
2683
|
-
this.destroyHrefHack();
|
2684
2445
|
},
|
2685
2446
|
|
2686
2447
|
|
@@ -2756,33 +2517,6 @@ var DragListener = FC.DragListener = Class.extend(ListenerMixin, MouseIgnorerMix
|
|
2756
2517
|
},
|
2757
2518
|
|
2758
2519
|
|
2759
|
-
// <A> HREF Hack
|
2760
|
-
// -----------------------------------------------------------------------------------------------------------------
|
2761
|
-
|
2762
|
-
|
2763
|
-
initHrefHack: function() {
|
2764
|
-
var subjectEl = this.subjectEl;
|
2765
|
-
|
2766
|
-
// remove a mousedown'd <a>'s href so it is not visited (IE8 bug)
|
2767
|
-
if ((this.subjectHref = subjectEl ? subjectEl.attr('href') : null)) {
|
2768
|
-
subjectEl.removeAttr('href');
|
2769
|
-
}
|
2770
|
-
},
|
2771
|
-
|
2772
|
-
|
2773
|
-
destroyHrefHack: function() {
|
2774
|
-
var subjectEl = this.subjectEl;
|
2775
|
-
var subjectHref = this.subjectHref;
|
2776
|
-
|
2777
|
-
// restore a mousedown'd <a>'s href (for IE8 bug)
|
2778
|
-
setTimeout(function() { // must be outside of the click's execution
|
2779
|
-
if (subjectHref) {
|
2780
|
-
subjectEl.attr('href', subjectHref);
|
2781
|
-
}
|
2782
|
-
}, 0);
|
2783
|
-
},
|
2784
|
-
|
2785
|
-
|
2786
2520
|
// Utils
|
2787
2521
|
// -----------------------------------------------------------------------------------------------------------------
|
2788
2522
|
|
@@ -3306,7 +3040,6 @@ var MouseFollower = Class.extend(ListenerMixin, {
|
|
3306
3040
|
var el = this.el;
|
3307
3041
|
|
3308
3042
|
if (!el) {
|
3309
|
-
this.sourceEl.width(); // hack to force IE8 to compute correct bounding box
|
3310
3043
|
el = this.el = this.sourceEl.clone()
|
3311
3044
|
.addClass(this.options.additionalClass || '')
|
3312
3045
|
.css({
|
@@ -3351,7 +3084,6 @@ var MouseFollower = Class.extend(ListenerMixin, {
|
|
3351
3084
|
|
3352
3085
|
// make sure origin info was computed
|
3353
3086
|
if (this.top0 === null) {
|
3354
|
-
this.sourceEl.width(); // hack to force IE8 to compute correct bounding box
|
3355
3087
|
sourceOffset = this.sourceEl.offset();
|
3356
3088
|
origin = this.el.offsetParent().offset();
|
3357
3089
|
this.top0 = sourceOffset.top - origin.top;
|
@@ -3405,6 +3137,9 @@ var MouseFollower = Class.extend(ListenerMixin, {
|
|
3405
3137
|
|
3406
3138
|
var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
|
3407
3139
|
|
3140
|
+
// self-config, overridable by subclasses
|
3141
|
+
hasDayInteractions: true, // can user click/select ranges of time?
|
3142
|
+
|
3408
3143
|
view: null, // a View object
|
3409
3144
|
isRTL: null, // shortcut to the view's isRTL option
|
3410
3145
|
|
@@ -3572,10 +3307,13 @@ var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
|
|
3572
3307
|
// Does other DOM-related initializations.
|
3573
3308
|
setElement: function(el) {
|
3574
3309
|
this.el = el;
|
3575
|
-
preventSelection(el);
|
3576
3310
|
|
3577
|
-
|
3578
|
-
|
3311
|
+
if (this.hasDayInteractions) {
|
3312
|
+
preventSelection(el);
|
3313
|
+
|
3314
|
+
this.bindDayHandler('touchstart', this.dayTouchStart);
|
3315
|
+
this.bindDayHandler('mousedown', this.dayMousedown);
|
3316
|
+
}
|
3579
3317
|
|
3580
3318
|
// attach event-element-related handlers. in Grid.events
|
3581
3319
|
// same garbage collection note as above.
|
@@ -3592,7 +3330,12 @@ var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
|
|
3592
3330
|
// jQuery will take care of unregistering them when removeElement gets called.
|
3593
3331
|
this.el.on(name, function(ev) {
|
3594
3332
|
if (
|
3595
|
-
!$(ev.target).is(
|
3333
|
+
!$(ev.target).is(
|
3334
|
+
_this.segSelector + ',' + // directly on an event element
|
3335
|
+
_this.segSelector + ' *,' + // within an event element
|
3336
|
+
'.fc-more,' + // a "more.." link
|
3337
|
+
'a[data-goto]' // a clickable nav link
|
3338
|
+
)
|
3596
3339
|
) {
|
3597
3340
|
return handler.call(_this, ev);
|
3598
3341
|
}
|
@@ -4044,6 +3787,9 @@ var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
|
|
4044
3787
|
|
4045
3788
|
Grid.mixin({
|
4046
3789
|
|
3790
|
+
// self-config, overridable by subclasses
|
3791
|
+
segSelector: '.fc-event-container > *', // what constitutes an event element?
|
3792
|
+
|
4047
3793
|
mousedOverSeg: null, // the segment object the user's mouse is over. null if over nothing
|
4048
3794
|
isDraggingSeg: false, // is a segment being dragged? boolean
|
4049
3795
|
isResizingSeg: false, // is a segment being resized? boolean
|
@@ -4265,7 +4011,7 @@ Grid.mixin({
|
|
4265
4011
|
bindSegHandlerToEl: function(el, name, handler) {
|
4266
4012
|
var _this = this;
|
4267
4013
|
|
4268
|
-
el.on(name,
|
4014
|
+
el.on(name, this.segSelector, function(ev) {
|
4269
4015
|
var seg = $(this).data('fc-seg'); // grab segment data. put there by View::renderEvents
|
4270
4016
|
|
4271
4017
|
// only call the handlers if there is not a drag/resize in progress
|
@@ -4277,7 +4023,10 @@ Grid.mixin({
|
|
4277
4023
|
|
4278
4024
|
|
4279
4025
|
handleSegClick: function(seg, ev) {
|
4280
|
-
|
4026
|
+
var res = this.view.trigger('eventClick', seg.el[0], seg.event, ev); // can return `false` to cancel
|
4027
|
+
if (res === false) {
|
4028
|
+
ev.preventDefault();
|
4029
|
+
}
|
4281
4030
|
},
|
4282
4031
|
|
4283
4032
|
|
@@ -4288,7 +4037,9 @@ Grid.mixin({
|
|
4288
4037
|
!this.mousedOverSeg
|
4289
4038
|
) {
|
4290
4039
|
this.mousedOverSeg = seg;
|
4291
|
-
|
4040
|
+
if (this.view.isEventResizable(seg.event)) {
|
4041
|
+
seg.el.addClass('fc-allow-mouse-resize');
|
4042
|
+
}
|
4292
4043
|
this.view.trigger('eventMouseover', seg.el[0], seg.event, ev);
|
4293
4044
|
}
|
4294
4045
|
},
|
@@ -4302,7 +4053,9 @@ Grid.mixin({
|
|
4302
4053
|
if (this.mousedOverSeg) {
|
4303
4054
|
seg = seg || this.mousedOverSeg; // if given no args, use the currently moused-over segment
|
4304
4055
|
this.mousedOverSeg = null;
|
4305
|
-
|
4056
|
+
if (this.view.isEventResizable(seg.event)) {
|
4057
|
+
seg.el.removeClass('fc-allow-mouse-resize');
|
4058
|
+
}
|
4306
4059
|
this.view.trigger('eventMouseout', seg.el[0], seg.event, ev);
|
4307
4060
|
}
|
4308
4061
|
},
|
@@ -4557,11 +4310,7 @@ Grid.mixin({
|
|
4557
4310
|
}
|
4558
4311
|
// othewise, work off existing values
|
4559
4312
|
else {
|
4560
|
-
dropLocation =
|
4561
|
-
start: event.start.clone(),
|
4562
|
-
end: event.end ? event.end.clone() : null,
|
4563
|
-
allDay: event.allDay // keep it the same
|
4564
|
-
};
|
4313
|
+
dropLocation = pluckEventDateProps(event);
|
4565
4314
|
}
|
4566
4315
|
|
4567
4316
|
dropLocation.start.add(delta);
|
@@ -4587,11 +4336,7 @@ Grid.mixin({
|
|
4587
4336
|
var opacity = this.view.opt('dragOpacity');
|
4588
4337
|
|
4589
4338
|
if (opacity != null) {
|
4590
|
-
els.
|
4591
|
-
// Don't use jQuery (will set an IE filter), do it the old fashioned way.
|
4592
|
-
// In IE8, a helper element will disappears if there's a filter.
|
4593
|
-
node.style.opacity = opacity;
|
4594
|
-
});
|
4339
|
+
els.css('opacity', opacity);
|
4595
4340
|
}
|
4596
4341
|
},
|
4597
4342
|
|
@@ -4757,8 +4502,11 @@ Grid.mixin({
|
|
4757
4502
|
disableCursor();
|
4758
4503
|
resizeLocation = null;
|
4759
4504
|
}
|
4760
|
-
// no change? (
|
4761
|
-
else if (
|
4505
|
+
// no change? (FYI, event dates might have zones)
|
4506
|
+
else if (
|
4507
|
+
resizeLocation.start.isSame(event.start.clone().stripZone()) &&
|
4508
|
+
resizeLocation.end.isSame(eventEnd.clone().stripZone())
|
4509
|
+
) {
|
4762
4510
|
resizeLocation = null;
|
4763
4511
|
}
|
4764
4512
|
}
|
@@ -4911,15 +4659,11 @@ Grid.mixin({
|
|
4911
4659
|
// Generic utility for generating the HTML classNames for an event segment's element
|
4912
4660
|
getSegClasses: function(seg, isDraggable, isResizable) {
|
4913
4661
|
var view = this.view;
|
4914
|
-
var event = seg.event;
|
4915
4662
|
var classes = [
|
4916
4663
|
'fc-event',
|
4917
4664
|
seg.isStart ? 'fc-start' : 'fc-not-start',
|
4918
4665
|
seg.isEnd ? 'fc-end' : 'fc-not-end'
|
4919
|
-
].concat(
|
4920
|
-
event.className,
|
4921
|
-
event.source ? event.source.className : []
|
4922
|
-
);
|
4666
|
+
].concat(this.getSegCustomClasses(seg));
|
4923
4667
|
|
4924
4668
|
if (isDraggable) {
|
4925
4669
|
classes.push('fc-draggable');
|
@@ -4929,7 +4673,7 @@ Grid.mixin({
|
|
4929
4673
|
}
|
4930
4674
|
|
4931
4675
|
// event is currently selected? attach a className.
|
4932
|
-
if (view.isEventSelected(event)) {
|
4676
|
+
if (view.isEventSelected(seg.event)) {
|
4933
4677
|
classes.push('fc-selected');
|
4934
4678
|
}
|
4935
4679
|
|
@@ -4937,38 +4681,78 @@ Grid.mixin({
|
|
4937
4681
|
},
|
4938
4682
|
|
4939
4683
|
|
4940
|
-
//
|
4941
|
-
|
4684
|
+
// List of classes that were defined by the caller of the API in some way
|
4685
|
+
getSegCustomClasses: function(seg) {
|
4942
4686
|
var event = seg.event;
|
4943
|
-
var view = this.view;
|
4944
|
-
var source = event.source || {};
|
4945
|
-
var eventColor = event.color;
|
4946
|
-
var sourceColor = source.color;
|
4947
|
-
var optionColor = view.opt('eventColor');
|
4948
4687
|
|
4688
|
+
return [].concat(
|
4689
|
+
event.className, // guaranteed to be an array
|
4690
|
+
event.source ? event.source.className : []
|
4691
|
+
);
|
4692
|
+
},
|
4693
|
+
|
4694
|
+
|
4695
|
+
// Utility for generating event skin-related CSS properties
|
4696
|
+
getSegSkinCss: function(seg) {
|
4949
4697
|
return {
|
4950
|
-
'background-color':
|
4951
|
-
|
4952
|
-
|
4953
|
-
source.backgroundColor ||
|
4954
|
-
sourceColor ||
|
4955
|
-
view.opt('eventBackgroundColor') ||
|
4956
|
-
optionColor,
|
4957
|
-
'border-color':
|
4958
|
-
event.borderColor ||
|
4959
|
-
eventColor ||
|
4960
|
-
source.borderColor ||
|
4961
|
-
sourceColor ||
|
4962
|
-
view.opt('eventBorderColor') ||
|
4963
|
-
optionColor,
|
4964
|
-
color:
|
4965
|
-
event.textColor ||
|
4966
|
-
source.textColor ||
|
4967
|
-
view.opt('eventTextColor')
|
4698
|
+
'background-color': this.getSegBackgroundColor(seg),
|
4699
|
+
'border-color': this.getSegBorderColor(seg),
|
4700
|
+
color: this.getSegTextColor(seg)
|
4968
4701
|
};
|
4969
4702
|
},
|
4970
4703
|
|
4971
4704
|
|
4705
|
+
// Queries for caller-specified color, then falls back to default
|
4706
|
+
getSegBackgroundColor: function(seg) {
|
4707
|
+
return seg.event.backgroundColor ||
|
4708
|
+
seg.event.color ||
|
4709
|
+
this.getSegDefaultBackgroundColor(seg);
|
4710
|
+
},
|
4711
|
+
|
4712
|
+
|
4713
|
+
getSegDefaultBackgroundColor: function(seg) {
|
4714
|
+
var source = seg.event.source || {};
|
4715
|
+
|
4716
|
+
return source.backgroundColor ||
|
4717
|
+
source.color ||
|
4718
|
+
this.view.opt('eventBackgroundColor') ||
|
4719
|
+
this.view.opt('eventColor');
|
4720
|
+
},
|
4721
|
+
|
4722
|
+
|
4723
|
+
// Queries for caller-specified color, then falls back to default
|
4724
|
+
getSegBorderColor: function(seg) {
|
4725
|
+
return seg.event.borderColor ||
|
4726
|
+
seg.event.color ||
|
4727
|
+
this.getSegDefaultBorderColor(seg);
|
4728
|
+
},
|
4729
|
+
|
4730
|
+
|
4731
|
+
getSegDefaultBorderColor: function(seg) {
|
4732
|
+
var source = seg.event.source || {};
|
4733
|
+
|
4734
|
+
return source.borderColor ||
|
4735
|
+
source.color ||
|
4736
|
+
this.view.opt('eventBorderColor') ||
|
4737
|
+
this.view.opt('eventColor');
|
4738
|
+
},
|
4739
|
+
|
4740
|
+
|
4741
|
+
// Queries for caller-specified color, then falls back to default
|
4742
|
+
getSegTextColor: function(seg) {
|
4743
|
+
return seg.event.textColor ||
|
4744
|
+
this.getSegDefaultTextColor(seg);
|
4745
|
+
},
|
4746
|
+
|
4747
|
+
|
4748
|
+
getSegDefaultTextColor: function(seg) {
|
4749
|
+
var source = seg.event.source || {};
|
4750
|
+
|
4751
|
+
return source.textColor ||
|
4752
|
+
this.view.opt('eventTextColor');
|
4753
|
+
},
|
4754
|
+
|
4755
|
+
|
4972
4756
|
/* Converting events -> eventRange -> eventSpan -> eventSegs
|
4973
4757
|
------------------------------------------------------------------------------------------------------------------*/
|
4974
4758
|
|
@@ -5036,20 +4820,25 @@ Grid.mixin({
|
|
5036
4820
|
// Generates the unzoned start/end dates an event appears to occupy
|
5037
4821
|
// Can accept an event "location" as well (which only has start/end and no allDay)
|
5038
4822
|
eventToRange: function(event) {
|
5039
|
-
|
5040
|
-
|
5041
|
-
|
4823
|
+
var calendar = this.view.calendar;
|
4824
|
+
var start = event.start.clone().stripZone();
|
4825
|
+
var end = (
|
5042
4826
|
event.end ?
|
5043
4827
|
event.end.clone() :
|
5044
4828
|
// derive the end from the start and allDay. compute allDay if necessary
|
5045
|
-
|
4829
|
+
calendar.getDefaultEventEnd(
|
5046
4830
|
event.allDay != null ?
|
5047
4831
|
event.allDay :
|
5048
4832
|
!event.start.hasTime(),
|
5049
4833
|
event.start
|
5050
4834
|
)
|
5051
|
-
).stripZone()
|
5052
|
-
|
4835
|
+
).stripZone();
|
4836
|
+
|
4837
|
+
// hack: dynamic locale change forgets to upate stored event localed
|
4838
|
+
calendar.localizeMoment(start);
|
4839
|
+
calendar.localizeMoment(end);
|
4840
|
+
|
4841
|
+
return { start: start, end: end };
|
5053
4842
|
},
|
5054
4843
|
|
5055
4844
|
|
@@ -5152,6 +4941,16 @@ Grid.mixin({
|
|
5152
4941
|
----------------------------------------------------------------------------------------------------------------------*/
|
5153
4942
|
|
5154
4943
|
|
4944
|
+
function pluckEventDateProps(event) {
|
4945
|
+
return {
|
4946
|
+
start: event.start.clone(),
|
4947
|
+
end: event.end ? event.end.clone() : null,
|
4948
|
+
allDay: event.allDay // keep it the same
|
4949
|
+
};
|
4950
|
+
}
|
4951
|
+
FC.pluckEventDateProps = pluckEventDateProps;
|
4952
|
+
|
4953
|
+
|
5155
4954
|
function isBgEvent(event) { // returns true if background OR inverse-background
|
5156
4955
|
var rendering = getEventRendering(event);
|
5157
4956
|
return rendering === 'background' || rendering === 'inverse-background';
|
@@ -5542,7 +5341,7 @@ var DayTableMixin = FC.DayTableMixin = {
|
|
5542
5341
|
|
5543
5342
|
return '' +
|
5544
5343
|
'<th class="fc-day-header ' + view.widgetHeaderClass + ' fc-' + dayIDs[date.day()] + '"' +
|
5545
|
-
(this.rowCnt
|
5344
|
+
(this.rowCnt === 1 ?
|
5546
5345
|
' data-date="' + date.format('YYYY-MM-DD') + '"' :
|
5547
5346
|
'') +
|
5548
5347
|
(colspan > 1 ?
|
@@ -5551,8 +5350,12 @@ var DayTableMixin = FC.DayTableMixin = {
|
|
5551
5350
|
(otherAttrs ?
|
5552
5351
|
' ' + otherAttrs :
|
5553
5352
|
'') +
|
5554
|
-
|
5555
|
-
|
5353
|
+
'>' +
|
5354
|
+
// don't make a link if the heading could represent multiple days, or if there's only one day (forceOff)
|
5355
|
+
view.buildGotoAnchorHtml(
|
5356
|
+
{ date: date, forceOff: this.rowCnt > 1 || this.colCnt === 1 },
|
5357
|
+
htmlEscape(date.format(this.colHeadFormat)) // inner HTML
|
5358
|
+
) +
|
5556
5359
|
'</th>';
|
5557
5360
|
},
|
5558
5361
|
|
@@ -5781,19 +5584,53 @@ var DayGrid = FC.DayGrid = Grid.extend(DayTableMixin, {
|
|
5781
5584
|
// Generates the HTML for the <td>s of the "number" row in the DayGrid's content skeleton.
|
5782
5585
|
// The number row will only exist if either day numbers or week numbers are turned on.
|
5783
5586
|
renderNumberCellHtml: function(date) {
|
5587
|
+
var html = '';
|
5784
5588
|
var classes;
|
5589
|
+
var weekCalcFirstDoW;
|
5785
5590
|
|
5786
|
-
if (!this.view.dayNumbersVisible) {
|
5591
|
+
if (!this.view.dayNumbersVisible && !this.view.cellWeekNumbersVisible) {
|
5592
|
+
// no numbers in day cell (week number must be along the side)
|
5787
5593
|
return '<td/>'; // will create an empty space above events :(
|
5788
5594
|
}
|
5789
5595
|
|
5790
5596
|
classes = this.getDayClasses(date);
|
5791
|
-
classes.unshift('fc-day-
|
5597
|
+
classes.unshift('fc-day-top');
|
5792
5598
|
|
5793
|
-
|
5794
|
-
|
5795
|
-
|
5796
|
-
'
|
5599
|
+
if (this.view.cellWeekNumbersVisible) {
|
5600
|
+
// To determine the day of week number change under ISO, we cannot
|
5601
|
+
// rely on moment.js methods such as firstDayOfWeek() or weekday(),
|
5602
|
+
// because they rely on the locale's dow (possibly overridden by
|
5603
|
+
// our firstDay option), which may not be Monday. We cannot change
|
5604
|
+
// dow, because that would affect the calendar start day as well.
|
5605
|
+
if (date._locale._fullCalendar_weekCalc === 'ISO') {
|
5606
|
+
weekCalcFirstDoW = 1; // Monday by ISO 8601 definition
|
5607
|
+
}
|
5608
|
+
else {
|
5609
|
+
weekCalcFirstDoW = date._locale.firstDayOfWeek();
|
5610
|
+
}
|
5611
|
+
}
|
5612
|
+
|
5613
|
+
html += '<td class="' + classes.join(' ') + '" data-date="' + date.format() + '">';
|
5614
|
+
|
5615
|
+
if (this.view.cellWeekNumbersVisible && (date.day() == weekCalcFirstDoW)) {
|
5616
|
+
html += this.view.buildGotoAnchorHtml(
|
5617
|
+
{ date: date, type: 'week' },
|
5618
|
+
{ 'class': 'fc-week-number' },
|
5619
|
+
date.format('w') // inner HTML
|
5620
|
+
);
|
5621
|
+
}
|
5622
|
+
|
5623
|
+
if (this.view.dayNumbersVisible) {
|
5624
|
+
html += this.view.buildGotoAnchorHtml(
|
5625
|
+
date,
|
5626
|
+
{ 'class': 'fc-day-number' },
|
5627
|
+
date.date() // inner HTML
|
5628
|
+
);
|
5629
|
+
}
|
5630
|
+
|
5631
|
+
html += '</td>';
|
5632
|
+
|
5633
|
+
return html;
|
5797
5634
|
},
|
5798
5635
|
|
5799
5636
|
|
@@ -6901,7 +6738,6 @@ var TimeGrid = FC.TimeGrid = Grid.extend(DayTableMixin, {
|
|
6901
6738
|
|
6902
6739
|
this.labelFormat =
|
6903
6740
|
input ||
|
6904
|
-
view.opt('axisFormat') || // deprecated
|
6905
6741
|
view.opt('smallTimeFormat'); // the computed default
|
6906
6742
|
|
6907
6743
|
input = view.opt('slotLabelInterval');
|
@@ -8133,6 +7969,62 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8133
7969
|
},
|
8134
7970
|
|
8135
7971
|
|
7972
|
+
getAllDayHtml: function() {
|
7973
|
+
return this.opt('allDayHtml') || htmlEscape(this.opt('allDayText'));
|
7974
|
+
},
|
7975
|
+
|
7976
|
+
|
7977
|
+
/* Navigation
|
7978
|
+
------------------------------------------------------------------------------------------------------------------*/
|
7979
|
+
|
7980
|
+
|
7981
|
+
// Generates HTML for an anchor to another view into the calendar.
|
7982
|
+
// Will either generate an <a> tag or a non-clickable <span> tag, depending on enabled settings.
|
7983
|
+
// `gotoOptions` can either be a moment input, or an object with the form:
|
7984
|
+
// { date, type, forceOff }
|
7985
|
+
// `type` is a view-type like "day" or "week". default value is "day".
|
7986
|
+
// `attrs` and `innerHtml` are use to generate the rest of the HTML tag.
|
7987
|
+
buildGotoAnchorHtml: function(gotoOptions, attrs, innerHtml) {
|
7988
|
+
var date, type, forceOff;
|
7989
|
+
var finalOptions;
|
7990
|
+
|
7991
|
+
if ($.isPlainObject(gotoOptions)) {
|
7992
|
+
date = gotoOptions.date;
|
7993
|
+
type = gotoOptions.type;
|
7994
|
+
forceOff = gotoOptions.forceOff;
|
7995
|
+
}
|
7996
|
+
else {
|
7997
|
+
date = gotoOptions; // a single moment input
|
7998
|
+
}
|
7999
|
+
date = FC.moment(date); // if a string, parse it
|
8000
|
+
|
8001
|
+
finalOptions = { // for serialization into the link
|
8002
|
+
date: date.format('YYYY-MM-DD'),
|
8003
|
+
type: type || 'day'
|
8004
|
+
};
|
8005
|
+
|
8006
|
+
if (typeof attrs === 'string') {
|
8007
|
+
innerHtml = attrs;
|
8008
|
+
attrs = null;
|
8009
|
+
}
|
8010
|
+
|
8011
|
+
attrs = attrs ? ' ' + attrsToStr(attrs) : ''; // will have a leading space
|
8012
|
+
innerHtml = innerHtml || '';
|
8013
|
+
|
8014
|
+
if (!forceOff && this.opt('navLinks')) {
|
8015
|
+
return '<a' + attrs +
|
8016
|
+
' data-goto="' + htmlEscape(JSON.stringify(finalOptions)) + '">' +
|
8017
|
+
innerHtml +
|
8018
|
+
'</a>';
|
8019
|
+
}
|
8020
|
+
else {
|
8021
|
+
return '<span' + attrs + '>' +
|
8022
|
+
innerHtml +
|
8023
|
+
'</span>';
|
8024
|
+
}
|
8025
|
+
},
|
8026
|
+
|
8027
|
+
|
8136
8028
|
/* Rendering
|
8137
8029
|
------------------------------------------------------------------------------------------------------------------*/
|
8138
8030
|
|
@@ -8628,14 +8520,24 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8628
8520
|
|
8629
8521
|
// Computes if the given event is allowed to be dragged by the user
|
8630
8522
|
isEventDraggable: function(event) {
|
8631
|
-
|
8523
|
+
return this.isEventStartEditable(event);
|
8524
|
+
},
|
8525
|
+
|
8632
8526
|
|
8527
|
+
isEventStartEditable: function(event) {
|
8633
8528
|
return firstDefined(
|
8634
8529
|
event.startEditable,
|
8635
|
-
source.startEditable,
|
8530
|
+
(event.source || {}).startEditable,
|
8636
8531
|
this.opt('eventStartEditable'),
|
8532
|
+
this.isEventGenerallyEditable(event)
|
8533
|
+
);
|
8534
|
+
},
|
8535
|
+
|
8536
|
+
|
8537
|
+
isEventGenerallyEditable: function(event) {
|
8538
|
+
return firstDefined(
|
8637
8539
|
event.editable,
|
8638
|
-
source.editable,
|
8540
|
+
(event.source || {}).editable,
|
8639
8541
|
this.opt('editable')
|
8640
8542
|
);
|
8641
8543
|
},
|
@@ -9135,7 +9037,7 @@ var Scroller = FC.Scroller = Class.extend({
|
|
9135
9037
|
var Calendar = FC.Calendar = Class.extend({
|
9136
9038
|
|
9137
9039
|
dirDefaults: null, // option defaults related to LTR or RTL
|
9138
|
-
|
9040
|
+
localeDefaults: null, // option defaults related to current locale
|
9139
9041
|
overrides: null, // option overrides given to the fullCalendar constructor
|
9140
9042
|
dynamicOverrides: null, // options set with dynamic setter method. higher precedence than view overrides.
|
9141
9043
|
options: null, // all defaults combined with overrides
|
@@ -9158,33 +9060,33 @@ var Calendar = FC.Calendar = Class.extend({
|
|
9158
9060
|
// Computes the flattened options hash for the calendar and assigns to `this.options`.
|
9159
9061
|
// Assumes this.overrides and this.dynamicOverrides have already been initialized.
|
9160
9062
|
populateOptionsHash: function() {
|
9161
|
-
var
|
9063
|
+
var locale, localeDefaults;
|
9162
9064
|
var isRTL, dirDefaults;
|
9163
9065
|
|
9164
|
-
|
9165
|
-
this.dynamicOverrides.
|
9166
|
-
this.overrides.
|
9066
|
+
locale = firstDefined( // explicit locale option given?
|
9067
|
+
this.dynamicOverrides.locale,
|
9068
|
+
this.overrides.locale
|
9167
9069
|
);
|
9168
|
-
|
9169
|
-
if (!
|
9170
|
-
|
9171
|
-
|
9070
|
+
localeDefaults = localeOptionHash[locale];
|
9071
|
+
if (!localeDefaults) { // explicit locale option not given or invalid?
|
9072
|
+
locale = Calendar.defaults.locale;
|
9073
|
+
localeDefaults = localeOptionHash[locale] || {};
|
9172
9074
|
}
|
9173
9075
|
|
9174
9076
|
isRTL = firstDefined( // based on options computed so far, is direction RTL?
|
9175
9077
|
this.dynamicOverrides.isRTL,
|
9176
9078
|
this.overrides.isRTL,
|
9177
|
-
|
9079
|
+
localeDefaults.isRTL,
|
9178
9080
|
Calendar.defaults.isRTL
|
9179
9081
|
);
|
9180
9082
|
dirDefaults = isRTL ? Calendar.rtlDefaults : {};
|
9181
9083
|
|
9182
9084
|
this.dirDefaults = dirDefaults;
|
9183
|
-
this.
|
9085
|
+
this.localeDefaults = localeDefaults;
|
9184
9086
|
this.options = mergeOptions([ // merge defaults and overrides. lowest to highest precedence
|
9185
9087
|
Calendar.defaults, // global defaults
|
9186
9088
|
dirDefaults,
|
9187
|
-
|
9089
|
+
localeDefaults,
|
9188
9090
|
this.overrides,
|
9189
9091
|
this.dynamicOverrides
|
9190
9092
|
]);
|
@@ -9300,7 +9202,7 @@ var Calendar = FC.Calendar = Class.extend({
|
|
9300
9202
|
Calendar.defaults, // global defaults
|
9301
9203
|
spec.defaults, // view's defaults (from ViewSubclass.defaults)
|
9302
9204
|
this.dirDefaults,
|
9303
|
-
this.
|
9205
|
+
this.localeDefaults, // locale and dir take precedence over view's defaults!
|
9304
9206
|
this.overrides, // calendar's overrides (options given to constructor)
|
9305
9207
|
spec.overrides, // view's overrides (view-specific options)
|
9306
9208
|
this.dynamicOverrides // dynamically set via setter. highest precedence
|
@@ -9317,6 +9219,9 @@ var Calendar = FC.Calendar = Class.extend({
|
|
9317
9219
|
function queryButtonText(options) {
|
9318
9220
|
var buttonText = options.buttonText || {};
|
9319
9221
|
return buttonText[requestedViewType] ||
|
9222
|
+
// view can decide to look up a certain key
|
9223
|
+
(spec.buttonTextKey ? buttonText[spec.buttonTextKey] : null) ||
|
9224
|
+
// a key like "month"
|
9320
9225
|
(spec.singleUnit ? buttonText[spec.singleUnit] : null);
|
9321
9226
|
}
|
9322
9227
|
|
@@ -9328,7 +9233,7 @@ var Calendar = FC.Calendar = Class.extend({
|
|
9328
9233
|
|
9329
9234
|
// highest to lowest priority. mirrors buildViewSpecOptions
|
9330
9235
|
spec.buttonTextDefault =
|
9331
|
-
queryButtonText(this.
|
9236
|
+
queryButtonText(this.localeDefaults) ||
|
9332
9237
|
queryButtonText(this.dirDefaults) ||
|
9333
9238
|
spec.defaults.buttonText || // a single string. from ViewSubclass.defaults
|
9334
9239
|
queryButtonText(Calendar.defaults) ||
|
@@ -9429,29 +9334,31 @@ function Calendar_constructor(element, overrides) {
|
|
9429
9334
|
t.dynamicOverrides = {};
|
9430
9335
|
t.viewSpecCache = {};
|
9431
9336
|
t.optionHandlers = {}; // for Calendar.options.js
|
9432
|
-
|
9433
|
-
// convert legacy options into non-legacy ones.
|
9434
|
-
// in the future, when this is removed, don't use `overrides` reference. make a copy.
|
9435
|
-
t.overrides = massageOverrides(overrides || {});
|
9337
|
+
t.overrides = $.extend({}, overrides); // make a copy
|
9436
9338
|
|
9437
9339
|
t.populateOptionsHash(); // sets this.options
|
9438
9340
|
|
9439
9341
|
|
9440
9342
|
|
9441
|
-
//
|
9343
|
+
// Locale-data Internals
|
9442
9344
|
// -----------------------------------------------------------------------------------
|
9443
|
-
// Apply overrides to the current
|
9345
|
+
// Apply overrides to the current locale's data
|
9444
9346
|
|
9445
9347
|
var localeData;
|
9446
9348
|
|
9447
9349
|
// Called immediately, and when any of the options change.
|
9448
9350
|
// Happens before any internal objects rebuild or rerender, because this is very core.
|
9449
9351
|
t.bindOptions([
|
9450
|
-
'
|
9451
|
-
], function(
|
9352
|
+
'locale', 'monthNames', 'monthNamesShort', 'dayNames', 'dayNamesShort', 'firstDay', 'weekNumberCalculation'
|
9353
|
+
], function(locale, monthNames, monthNamesShort, dayNames, dayNamesShort, firstDay, weekNumberCalculation) {
|
9354
|
+
|
9355
|
+
// normalize
|
9356
|
+
if (weekNumberCalculation === 'iso') {
|
9357
|
+
weekNumberCalculation = 'ISO'; // normalize
|
9358
|
+
}
|
9452
9359
|
|
9453
9360
|
localeData = createObject( // make a cheap copy
|
9454
|
-
getMomentLocaleData(
|
9361
|
+
getMomentLocaleData(locale) // will fall back to en
|
9455
9362
|
);
|
9456
9363
|
|
9457
9364
|
if (monthNames) {
|
@@ -9466,15 +9373,16 @@ function Calendar_constructor(element, overrides) {
|
|
9466
9373
|
if (dayNamesShort) {
|
9467
9374
|
localeData._weekdaysShort = dayNamesShort;
|
9468
9375
|
}
|
9376
|
+
|
9377
|
+
if (firstDay == null && weekNumberCalculation === 'ISO') {
|
9378
|
+
firstDay = 1;
|
9379
|
+
}
|
9469
9380
|
if (firstDay != null) {
|
9470
9381
|
var _week = createObject(localeData._week); // _week: { dow: # }
|
9471
9382
|
_week.dow = firstDay;
|
9472
9383
|
localeData._week = _week;
|
9473
9384
|
}
|
9474
9385
|
|
9475
|
-
if (weekNumberCalculation === 'iso') {
|
9476
|
-
weekNumberCalculation = 'ISO'; // normalize
|
9477
|
-
}
|
9478
9386
|
if ( // whitelist certain kinds of input
|
9479
9387
|
weekNumberCalculation === 'ISO' ||
|
9480
9388
|
weekNumberCalculation === 'local' ||
|
@@ -9491,7 +9399,6 @@ function Calendar_constructor(element, overrides) {
|
|
9491
9399
|
});
|
9492
9400
|
|
9493
9401
|
|
9494
|
-
|
9495
9402
|
// Calendar-specific Date Utilities
|
9496
9403
|
// -----------------------------------------------------------------------------------
|
9497
9404
|
|
@@ -9500,7 +9407,7 @@ function Calendar_constructor(element, overrides) {
|
|
9500
9407
|
t.defaultTimedEventDuration = moment.duration(t.options.defaultTimedEventDuration);
|
9501
9408
|
|
9502
9409
|
|
9503
|
-
// Builds a moment using the settings of the current calendar: timezone and
|
9410
|
+
// Builds a moment using the settings of the current calendar: timezone and locale.
|
9504
9411
|
// Accepts anything the vanilla moment() constructor accepts.
|
9505
9412
|
t.moment = function() {
|
9506
9413
|
var mom;
|
@@ -9528,13 +9435,9 @@ function Calendar_constructor(element, overrides) {
|
|
9528
9435
|
|
9529
9436
|
// Updates the given moment's locale settings to the current calendar locale settings.
|
9530
9437
|
function localizeMoment(mom) {
|
9531
|
-
|
9532
|
-
mom._locale = localeData;
|
9533
|
-
}
|
9534
|
-
else { // pre-moment-2.8
|
9535
|
-
mom._lang = localeData;
|
9536
|
-
}
|
9438
|
+
mom._locale = localeData;
|
9537
9439
|
}
|
9440
|
+
t.localizeMoment = localizeMoment;
|
9538
9441
|
|
9539
9442
|
|
9540
9443
|
// Returns a boolean about whether or not the calendar knows how to calculate
|
@@ -9611,8 +9514,7 @@ function Calendar_constructor(element, overrides) {
|
|
9611
9514
|
// Produces a human-readable string for the given duration.
|
9612
9515
|
// Side-effect: changes the locale of the given duration.
|
9613
9516
|
t.humanizeDuration = function(duration) {
|
9614
|
-
return
|
9615
|
-
.humanize();
|
9517
|
+
return duration.locale(t.options.locale).humanize();
|
9616
9518
|
};
|
9617
9519
|
|
9618
9520
|
|
@@ -9674,16 +9576,37 @@ function Calendar_constructor(element, overrides) {
|
|
9674
9576
|
function initialRender() {
|
9675
9577
|
element.addClass('fc');
|
9676
9578
|
|
9677
|
-
//
|
9678
|
-
|
9679
|
-
|
9680
|
-
|
9681
|
-
|
9579
|
+
// event delegation for nav links
|
9580
|
+
element.on('click.fc', 'a[data-goto]', function(ev) {
|
9581
|
+
var anchorEl = $(this);
|
9582
|
+
var gotoOptions = anchorEl.data('goto'); // will automatically parse JSON
|
9583
|
+
var date = t.moment(gotoOptions.date);
|
9584
|
+
var viewType = gotoOptions.type;
|
9585
|
+
|
9586
|
+
// property like "navLinkDayClick". might be a string or a function
|
9587
|
+
var customAction = currentView.opt('navLink' + capitaliseFirstLetter(viewType) + 'Click');
|
9588
|
+
|
9589
|
+
if (typeof customAction === 'function') {
|
9590
|
+
customAction(date, ev);
|
9591
|
+
}
|
9592
|
+
else {
|
9593
|
+
if (typeof customAction === 'string') {
|
9594
|
+
viewType = customAction;
|
9595
|
+
}
|
9596
|
+
zoomTo(date, viewType);
|
9597
|
+
}
|
9598
|
+
});
|
9599
|
+
|
9600
|
+
// called immediately, and upon option change
|
9601
|
+
t.bindOption('theme', function(theme) {
|
9602
|
+
tm = theme ? 'ui' : 'fc'; // affects a larger scope
|
9603
|
+
element.toggleClass('ui-widget', theme);
|
9604
|
+
element.toggleClass('fc-unthemed', !theme);
|
9682
9605
|
});
|
9683
9606
|
|
9684
9607
|
// called immediately, and upon option change.
|
9685
|
-
// HACK:
|
9686
|
-
t.bindOptions([ 'isRTL', '
|
9608
|
+
// HACK: locale often affects isRTL, so we explicitly listen to that too.
|
9609
|
+
t.bindOptions([ 'isRTL', 'locale' ], function(isRTL) {
|
9687
9610
|
element.toggleClass('fc-ltr', !isRTL);
|
9688
9611
|
element.toggleClass('fc-rtl', isRTL);
|
9689
9612
|
});
|
@@ -9724,6 +9647,8 @@ function Calendar_constructor(element, overrides) {
|
|
9724
9647
|
content.remove();
|
9725
9648
|
element.removeClass('fc fc-ltr fc-rtl fc-unthemed ui-widget');
|
9726
9649
|
|
9650
|
+
element.off('.fc'); // unbind nav link handlers
|
9651
|
+
|
9727
9652
|
if (windowResizeProxy) {
|
9728
9653
|
$(window).unbind('resize', windowResizeProxy);
|
9729
9654
|
}
|
@@ -9772,7 +9697,10 @@ function Calendar_constructor(element, overrides) {
|
|
9772
9697
|
// render or rerender the view
|
9773
9698
|
if (
|
9774
9699
|
!currentView.displaying ||
|
9775
|
-
!
|
9700
|
+
!( // NOT within interval range signals an implicit date window change
|
9701
|
+
date >= currentView.intervalStart &&
|
9702
|
+
date < currentView.intervalEnd
|
9703
|
+
)
|
9776
9704
|
) {
|
9777
9705
|
if (elementVisible()) {
|
9778
9706
|
|
@@ -9971,7 +9899,8 @@ function Calendar_constructor(element, overrides) {
|
|
9971
9899
|
|
9972
9900
|
function updateTodayButton() {
|
9973
9901
|
var now = t.getNow();
|
9974
|
-
|
9902
|
+
|
9903
|
+
if (now >= currentView.intervalStart && now < currentView.intervalEnd) {
|
9975
9904
|
header.disableButton('today');
|
9976
9905
|
}
|
9977
9906
|
else {
|
@@ -10258,7 +10187,7 @@ Calendar.mixin({
|
|
10258
10187
|
Calendar.defaults = {
|
10259
10188
|
|
10260
10189
|
titleRangeSeparator: ' \u2013 ', // en dash
|
10261
|
-
monthYearFormat: 'MMMM YYYY', // required for en. other
|
10190
|
+
monthYearFormat: 'MMMM YYYY', // required for en. other locales rely on datepicker computable option
|
10262
10191
|
|
10263
10192
|
defaultTimedEventDuration: '02:00:00',
|
10264
10193
|
defaultAllDayEventDuration: { days: 1 },
|
@@ -10315,6 +10244,8 @@ Calendar.defaults = {
|
|
10315
10244
|
prevYear: 'left-double-arrow',
|
10316
10245
|
nextYear: 'right-double-arrow'
|
10317
10246
|
},
|
10247
|
+
|
10248
|
+
allDayText: 'all-day',
|
10318
10249
|
|
10319
10250
|
// jquery-ui theming
|
10320
10251
|
theme: false,
|
@@ -10350,7 +10281,7 @@ Calendar.defaults = {
|
|
10350
10281
|
};
|
10351
10282
|
|
10352
10283
|
|
10353
|
-
Calendar.englishDefaults = { // used by
|
10284
|
+
Calendar.englishDefaults = { // used by locale.js
|
10354
10285
|
dayPopoverFormat: 'dddd, MMMM D'
|
10355
10286
|
};
|
10356
10287
|
|
@@ -10377,19 +10308,18 @@ Calendar.rtlDefaults = { // right-to-left defaults
|
|
10377
10308
|
|
10378
10309
|
;;
|
10379
10310
|
|
10380
|
-
var
|
10311
|
+
var localeOptionHash = FC.locales = {}; // initialize and expose
|
10381
10312
|
|
10382
10313
|
|
10383
|
-
// TODO: document the structure and ordering of a FullCalendar
|
10384
|
-
// TODO: rename everything "lang" to "locale", like what the moment project did
|
10314
|
+
// TODO: document the structure and ordering of a FullCalendar locale file
|
10385
10315
|
|
10386
10316
|
|
10387
10317
|
// Initialize jQuery UI datepicker translations while using some of the translations
|
10388
|
-
// Will set this as the default
|
10389
|
-
FC.
|
10318
|
+
// Will set this as the default locales for datepicker.
|
10319
|
+
FC.datepickerLocale = function(localeCode, dpLocaleCode, dpOptions) {
|
10390
10320
|
|
10391
|
-
// get the FullCalendar internal option hash for this
|
10392
|
-
var fcOptions =
|
10321
|
+
// get the FullCalendar internal option hash for this locale. create if necessary
|
10322
|
+
var fcOptions = localeOptionHash[localeCode] || (localeOptionHash[localeCode] = {});
|
10393
10323
|
|
10394
10324
|
// transfer some simple options from datepicker to fc
|
10395
10325
|
fcOptions.isRTL = dpOptions.isRTL;
|
@@ -10403,15 +10333,15 @@ FC.datepickerLang = function(langCode, dpLangCode, dpOptions) {
|
|
10403
10333
|
// is jQuery UI Datepicker is on the page?
|
10404
10334
|
if ($.datepicker) {
|
10405
10335
|
|
10406
|
-
// Register the
|
10407
|
-
// FullCalendar and MomentJS use
|
10408
|
-
// does it like "pt-BR" or if it doesn't have the
|
10409
|
-
// Make an alias so the
|
10410
|
-
$.datepicker.regional[
|
10411
|
-
$.datepicker.regional[
|
10336
|
+
// Register the locale data.
|
10337
|
+
// FullCalendar and MomentJS use locale codes like "pt-br" but Datepicker
|
10338
|
+
// does it like "pt-BR" or if it doesn't have the locale, maybe just "pt".
|
10339
|
+
// Make an alias so the locale can be referenced either way.
|
10340
|
+
$.datepicker.regional[dpLocaleCode] =
|
10341
|
+
$.datepicker.regional[localeCode] = // alias
|
10412
10342
|
dpOptions;
|
10413
10343
|
|
10414
|
-
// Alias 'en' to the default
|
10344
|
+
// Alias 'en' to the default locale data. Do this every time.
|
10415
10345
|
$.datepicker.regional.en = $.datepicker.regional[''];
|
10416
10346
|
|
10417
10347
|
// Set as Datepicker's global defaults.
|
@@ -10420,35 +10350,35 @@ FC.datepickerLang = function(langCode, dpLangCode, dpOptions) {
|
|
10420
10350
|
};
|
10421
10351
|
|
10422
10352
|
|
10423
|
-
// Sets FullCalendar-specific translations. Will set the
|
10424
|
-
FC.
|
10353
|
+
// Sets FullCalendar-specific translations. Will set the locales as the global default.
|
10354
|
+
FC.locale = function(localeCode, newFcOptions) {
|
10425
10355
|
var fcOptions;
|
10426
10356
|
var momOptions;
|
10427
10357
|
|
10428
|
-
// get the FullCalendar internal option hash for this
|
10429
|
-
fcOptions =
|
10358
|
+
// get the FullCalendar internal option hash for this locale. create if necessary
|
10359
|
+
fcOptions = localeOptionHash[localeCode] || (localeOptionHash[localeCode] = {});
|
10430
10360
|
|
10431
|
-
// provided new options for this
|
10361
|
+
// provided new options for this locales? merge them in
|
10432
10362
|
if (newFcOptions) {
|
10433
|
-
fcOptions =
|
10363
|
+
fcOptions = localeOptionHash[localeCode] = mergeOptions([ fcOptions, newFcOptions ]);
|
10434
10364
|
}
|
10435
10365
|
|
10436
|
-
// compute
|
10366
|
+
// compute locale options that weren't defined.
|
10437
10367
|
// always do this. newFcOptions can be undefined when initializing from i18n file,
|
10438
10368
|
// so no way to tell if this is an initialization or a default-setting.
|
10439
|
-
momOptions = getMomentLocaleData(
|
10369
|
+
momOptions = getMomentLocaleData(localeCode); // will fall back to en
|
10440
10370
|
$.each(momComputableOptions, function(name, func) {
|
10441
10371
|
if (fcOptions[name] == null) {
|
10442
10372
|
fcOptions[name] = func(momOptions, fcOptions);
|
10443
10373
|
}
|
10444
10374
|
});
|
10445
10375
|
|
10446
|
-
// set it as the default
|
10447
|
-
Calendar.defaults.
|
10376
|
+
// set it as the default locale for FullCalendar
|
10377
|
+
Calendar.defaults.locale = localeCode;
|
10448
10378
|
};
|
10449
10379
|
|
10450
10380
|
|
10451
|
-
// NOTE: can't guarantee any of these computations will run because not every
|
10381
|
+
// NOTE: can't guarantee any of these computations will run because not every locale has datepicker
|
10452
10382
|
// configs, so make sure there are English fallbacks for these in the defaults file.
|
10453
10383
|
var dpComputableOptions = {
|
10454
10384
|
|
@@ -10498,7 +10428,7 @@ var momComputableOptions = {
|
|
10498
10428
|
smallTimeFormat: function(momOptions) {
|
10499
10429
|
return momOptions.longDateFormat('LT')
|
10500
10430
|
.replace(':mm', '(:mm)')
|
10501
|
-
.replace(/(\Wmm)$/, '($1)') // like above, but for foreign
|
10431
|
+
.replace(/(\Wmm)$/, '($1)') // like above, but for foreign locales
|
10502
10432
|
.replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
|
10503
10433
|
},
|
10504
10434
|
|
@@ -10506,7 +10436,7 @@ var momComputableOptions = {
|
|
10506
10436
|
extraSmallTimeFormat: function(momOptions) {
|
10507
10437
|
return momOptions.longDateFormat('LT')
|
10508
10438
|
.replace(':mm', '(:mm)')
|
10509
|
-
.replace(/(\Wmm)$/, '($1)') // like above, but for foreign
|
10439
|
+
.replace(/(\Wmm)$/, '($1)') // like above, but for foreign locales
|
10510
10440
|
.replace(/\s*a$/i, 't'); // convert to AM/PM/am/pm to lowercase one-letter. remove any spaces beforehand
|
10511
10441
|
},
|
10512
10442
|
|
@@ -10514,7 +10444,7 @@ var momComputableOptions = {
|
|
10514
10444
|
hourFormat: function(momOptions) {
|
10515
10445
|
return momOptions.longDateFormat('LT')
|
10516
10446
|
.replace(':mm', '')
|
10517
|
-
.replace(/(\Wmm)$/, '') // like above, but for foreign
|
10447
|
+
.replace(/(\Wmm)$/, '') // like above, but for foreign locales
|
10518
10448
|
.replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
|
10519
10449
|
},
|
10520
10450
|
|
@@ -10528,7 +10458,7 @@ var momComputableOptions = {
|
|
10528
10458
|
|
10529
10459
|
|
10530
10460
|
// options that should be computed off live calendar options (considers override options)
|
10531
|
-
// TODO: best place for this? related to
|
10461
|
+
// TODO: best place for this? related to locale?
|
10532
10462
|
// TODO: flipping text based on isRTL is a bad idea because the CSS `direction` might want to handle it
|
10533
10463
|
var instanceComputableOptions = {
|
10534
10464
|
|
@@ -10565,17 +10495,14 @@ function populateInstanceComputableOptions(options) {
|
|
10565
10495
|
|
10566
10496
|
|
10567
10497
|
// Returns moment's internal locale data. If doesn't exist, returns English.
|
10568
|
-
|
10569
|
-
|
10570
|
-
var func = moment.localeData || moment.langData;
|
10571
|
-
return func.call(moment, langCode) ||
|
10572
|
-
func.call(moment, 'en'); // the newer localData could return null, so fall back to en
|
10498
|
+
function getMomentLocaleData(localeCode) {
|
10499
|
+
return moment.localeData(localeCode) || moment.localeData('en');
|
10573
10500
|
}
|
10574
10501
|
|
10575
10502
|
|
10576
10503
|
// Initialize English by forcing computation of moment-derived options.
|
10577
10504
|
// Also, sets it as the default.
|
10578
|
-
FC.
|
10505
|
+
FC.locale('en', Calendar.englishDefaults);
|
10579
10506
|
|
10580
10507
|
;;
|
10581
10508
|
|
@@ -11884,78 +11811,134 @@ function EventManager() { // assumed to be a calendar
|
|
11884
11811
|
}
|
11885
11812
|
|
11886
11813
|
|
11887
|
-
|
11888
|
-
|
11814
|
+
t.getEventCache = function() {
|
11815
|
+
return cache;
|
11816
|
+
};
|
11889
11817
|
|
11890
|
-
|
11891
|
-
t.isExternalSpanAllowed = isExternalSpanAllowed;
|
11892
|
-
t.isSelectionSpanAllowed = isSelectionSpanAllowed;
|
11818
|
+
}
|
11893
11819
|
|
11894
11820
|
|
11895
|
-
|
11896
|
-
|
11897
|
-
|
11898
|
-
|
11899
|
-
event.constraint,
|
11900
|
-
source.constraint,
|
11901
|
-
t.options.eventConstraint
|
11902
|
-
);
|
11903
|
-
var overlap = firstDefined(
|
11904
|
-
event.overlap,
|
11905
|
-
source.overlap,
|
11906
|
-
t.options.eventOverlap
|
11907
|
-
);
|
11908
|
-
return isSpanAllowed(span, constraint, overlap, event);
|
11909
|
-
}
|
11821
|
+
// hook for external libs to manipulate event properties upon creation.
|
11822
|
+
// should manipulate the event in-place.
|
11823
|
+
Calendar.prototype.normalizeEvent = function(event) {
|
11824
|
+
};
|
11910
11825
|
|
11911
11826
|
|
11912
|
-
|
11913
|
-
|
11914
|
-
|
11915
|
-
|
11827
|
+
// Does the given span (start, end, and other location information)
|
11828
|
+
// fully contain the other?
|
11829
|
+
Calendar.prototype.spanContainsSpan = function(outerSpan, innerSpan) {
|
11830
|
+
var eventStart = outerSpan.start.clone().stripZone();
|
11831
|
+
var eventEnd = this.getEventEnd(outerSpan).stripZone();
|
11916
11832
|
|
11917
|
-
|
11918
|
-
|
11919
|
-
eventInput = $.extend({}, eventProps, eventLocation);
|
11920
|
-
event = expandEvent(buildEventFromInput(eventInput))[0];
|
11921
|
-
}
|
11833
|
+
return innerSpan.start >= eventStart && innerSpan.end <= eventEnd;
|
11834
|
+
};
|
11922
11835
|
|
11923
|
-
if (event) {
|
11924
|
-
return isEventSpanAllowed(eventSpan, event);
|
11925
|
-
}
|
11926
|
-
else { // treat it as a selection
|
11927
11836
|
|
11928
|
-
|
11837
|
+
// Returns a list of events that the given event should be compared against when being considered for a move to
|
11838
|
+
// the specified span. Attached to the Calendar's prototype because EventManager is a mixin for a Calendar.
|
11839
|
+
Calendar.prototype.getPeerEvents = function(span, event) {
|
11840
|
+
var cache = this.getEventCache();
|
11841
|
+
var peerEvents = [];
|
11842
|
+
var i, otherEvent;
|
11843
|
+
|
11844
|
+
for (i = 0; i < cache.length; i++) {
|
11845
|
+
otherEvent = cache[i];
|
11846
|
+
if (
|
11847
|
+
!event ||
|
11848
|
+
event._id !== otherEvent._id // don't compare the event to itself or other related [repeating] events
|
11849
|
+
) {
|
11850
|
+
peerEvents.push(otherEvent);
|
11929
11851
|
}
|
11930
11852
|
}
|
11931
11853
|
|
11854
|
+
return peerEvents;
|
11855
|
+
};
|
11856
|
+
|
11857
|
+
|
11858
|
+
// updates the "backup" properties, which are preserved in order to compute diffs later on.
|
11859
|
+
function backupEventDates(event) {
|
11860
|
+
event._allDay = event.allDay;
|
11861
|
+
event._start = event.start.clone();
|
11862
|
+
event._end = event.end ? event.end.clone() : null;
|
11863
|
+
}
|
11864
|
+
|
11865
|
+
|
11866
|
+
/* Overlapping / Constraining
|
11867
|
+
-----------------------------------------------------------------------------------------*/
|
11868
|
+
|
11869
|
+
|
11870
|
+
// Determines if the given event can be relocated to the given span (unzoned start/end with other misc data)
|
11871
|
+
Calendar.prototype.isEventSpanAllowed = function(span, event) {
|
11872
|
+
var source = event.source || {};
|
11932
11873
|
|
11933
|
-
|
11934
|
-
|
11935
|
-
|
11874
|
+
var constraint = firstDefined(
|
11875
|
+
event.constraint,
|
11876
|
+
source.constraint,
|
11877
|
+
this.options.eventConstraint
|
11878
|
+
);
|
11879
|
+
|
11880
|
+
var overlap = firstDefined(
|
11881
|
+
event.overlap,
|
11882
|
+
source.overlap,
|
11883
|
+
this.options.eventOverlap
|
11884
|
+
);
|
11885
|
+
|
11886
|
+
return this.isSpanAllowed(span, constraint, overlap, event) &&
|
11887
|
+
(!this.options.eventAllow || this.options.eventAllow(span, event) !== false);
|
11888
|
+
};
|
11889
|
+
|
11890
|
+
|
11891
|
+
// Determines if an external event can be relocated to the given span (unzoned start/end with other misc data)
|
11892
|
+
Calendar.prototype.isExternalSpanAllowed = function(eventSpan, eventLocation, eventProps) {
|
11893
|
+
var eventInput;
|
11894
|
+
var event;
|
11895
|
+
|
11896
|
+
// note: very similar logic is in View's reportExternalDrop
|
11897
|
+
if (eventProps) {
|
11898
|
+
eventInput = $.extend({}, eventProps, eventLocation);
|
11899
|
+
event = this.expandEvent(
|
11900
|
+
this.buildEventFromInput(eventInput)
|
11901
|
+
)[0];
|
11936
11902
|
}
|
11937
11903
|
|
11904
|
+
if (event) {
|
11905
|
+
return this.isEventSpanAllowed(eventSpan, event);
|
11906
|
+
}
|
11907
|
+
else { // treat it as a selection
|
11938
11908
|
|
11939
|
-
|
11940
|
-
|
11941
|
-
|
11942
|
-
|
11943
|
-
|
11944
|
-
|
11945
|
-
|
11946
|
-
|
11947
|
-
|
11909
|
+
return this.isSelectionSpanAllowed(eventSpan);
|
11910
|
+
}
|
11911
|
+
};
|
11912
|
+
|
11913
|
+
|
11914
|
+
// Determines the given span (unzoned start/end with other misc data) can be selected.
|
11915
|
+
Calendar.prototype.isSelectionSpanAllowed = function(span) {
|
11916
|
+
return this.isSpanAllowed(span, this.options.selectConstraint, this.options.selectOverlap) &&
|
11917
|
+
(!this.options.selectAllow || this.options.selectAllow(span) !== false);
|
11918
|
+
};
|
11948
11919
|
|
11949
|
-
// the range must be fully contained by at least one of produced constraint events
|
11950
|
-
if (constraint != null) {
|
11951
11920
|
|
11952
|
-
|
11953
|
-
|
11954
|
-
|
11921
|
+
// Returns true if the given span (caused by an event drop/resize or a selection) is allowed to exist
|
11922
|
+
// according to the constraint/overlap settings.
|
11923
|
+
// `event` is not required if checking a selection.
|
11924
|
+
Calendar.prototype.isSpanAllowed = function(span, constraint, overlap, event) {
|
11925
|
+
var constraintEvents;
|
11926
|
+
var anyContainment;
|
11927
|
+
var peerEvents;
|
11928
|
+
var i, peerEvent;
|
11929
|
+
var peerOverlap;
|
11930
|
+
|
11931
|
+
// the range must be fully contained by at least one of produced constraint events
|
11932
|
+
if (constraint != null) {
|
11933
|
+
|
11934
|
+
// not treated as an event! intermediate data structure
|
11935
|
+
// TODO: use ranges in the future
|
11936
|
+
constraintEvents = this.constraintToEvents(constraint);
|
11937
|
+
if (constraintEvents) { // not invalid
|
11955
11938
|
|
11956
11939
|
anyContainment = false;
|
11957
11940
|
for (i = 0; i < constraintEvents.length; i++) {
|
11958
|
-
if (
|
11941
|
+
if (this.spanContainsSpan(constraintEvents[i], span)) {
|
11959
11942
|
anyContainment = true;
|
11960
11943
|
break;
|
11961
11944
|
}
|
@@ -11965,127 +11948,81 @@ function EventManager() { // assumed to be a calendar
|
|
11965
11948
|
return false;
|
11966
11949
|
}
|
11967
11950
|
}
|
11951
|
+
}
|
11968
11952
|
|
11969
|
-
|
11953
|
+
peerEvents = this.getPeerEvents(span, event);
|
11970
11954
|
|
11971
|
-
|
11972
|
-
|
11955
|
+
for (i = 0; i < peerEvents.length; i++) {
|
11956
|
+
peerEvent = peerEvents[i];
|
11973
11957
|
|
11974
|
-
|
11975
|
-
|
11958
|
+
// there needs to be an actual intersection before disallowing anything
|
11959
|
+
if (this.eventIntersectsRange(peerEvent, span)) {
|
11960
|
+
|
11961
|
+
// evaluate overlap for the given range and short-circuit if necessary
|
11962
|
+
if (overlap === false) {
|
11963
|
+
return false;
|
11964
|
+
}
|
11965
|
+
// if the event's overlap is a test function, pass the peer event in question as the first param
|
11966
|
+
else if (typeof overlap === 'function' && !overlap(peerEvent, event)) {
|
11967
|
+
return false;
|
11968
|
+
}
|
11976
11969
|
|
11977
|
-
|
11978
|
-
|
11970
|
+
// if we are computing if the given range is allowable for an event, consider the other event's
|
11971
|
+
// EventObject-specific or Source-specific `overlap` property
|
11972
|
+
if (event) {
|
11973
|
+
peerOverlap = firstDefined(
|
11974
|
+
peerEvent.overlap,
|
11975
|
+
(peerEvent.source || {}).overlap
|
11976
|
+
// we already considered the global `eventOverlap`
|
11977
|
+
);
|
11978
|
+
if (peerOverlap === false) {
|
11979
11979
|
return false;
|
11980
11980
|
}
|
11981
|
-
// if the event's overlap is a test function, pass the
|
11982
|
-
|
11981
|
+
// if the peer event's overlap is a test function, pass the subject event as the first param
|
11982
|
+
if (typeof peerOverlap === 'function' && !peerOverlap(event, peerEvent)) {
|
11983
11983
|
return false;
|
11984
11984
|
}
|
11985
|
-
|
11986
|
-
// if we are computing if the given range is allowable for an event, consider the other event's
|
11987
|
-
// EventObject-specific or Source-specific `overlap` property
|
11988
|
-
if (event) {
|
11989
|
-
peerOverlap = firstDefined(
|
11990
|
-
peerEvent.overlap,
|
11991
|
-
(peerEvent.source || {}).overlap
|
11992
|
-
// we already considered the global `eventOverlap`
|
11993
|
-
);
|
11994
|
-
if (peerOverlap === false) {
|
11995
|
-
return false;
|
11996
|
-
}
|
11997
|
-
// if the peer event's overlap is a test function, pass the subject event as the first param
|
11998
|
-
if (typeof peerOverlap === 'function' && !peerOverlap(event, peerEvent)) {
|
11999
|
-
return false;
|
12000
|
-
}
|
12001
|
-
}
|
12002
11985
|
}
|
12003
11986
|
}
|
12004
|
-
|
12005
|
-
return true;
|
12006
11987
|
}
|
12007
11988
|
|
11989
|
+
return true;
|
11990
|
+
};
|
12008
11991
|
|
12009
|
-
// Given an event input from the API, produces an array of event objects. Possible event inputs:
|
12010
|
-
// 'businessHours'
|
12011
|
-
// An event ID (number or string)
|
12012
|
-
// An object with specific start/end dates or a recurring event (like what businessHours accepts)
|
12013
|
-
function constraintToEvents(constraintInput) {
|
12014
|
-
|
12015
|
-
if (constraintInput === 'businessHours') {
|
12016
|
-
return t.getCurrentBusinessHourEvents();
|
12017
|
-
}
|
12018
11992
|
|
12019
|
-
|
12020
|
-
|
12021
|
-
|
11993
|
+
// Given an event input from the API, produces an array of event objects. Possible event inputs:
|
11994
|
+
// 'businessHours'
|
11995
|
+
// An event ID (number or string)
|
11996
|
+
// An object with specific start/end dates or a recurring event (like what businessHours accepts)
|
11997
|
+
Calendar.prototype.constraintToEvents = function(constraintInput) {
|
12022
11998
|
|
12023
|
-
|
11999
|
+
if (constraintInput === 'businessHours') {
|
12000
|
+
return this.getCurrentBusinessHourEvents();
|
12024
12001
|
}
|
12025
12002
|
|
12026
|
-
|
12027
|
-
|
12028
|
-
|
12029
|
-
|
12030
|
-
|
12031
|
-
|
12032
|
-
|
12033
|
-
return range.start < eventEnd && range.end > eventStart;
|
12003
|
+
if (typeof constraintInput === 'object') {
|
12004
|
+
if (constraintInput.start != null) { // needs to be event-like input
|
12005
|
+
return this.expandEvent(this.buildEventFromInput(constraintInput));
|
12006
|
+
}
|
12007
|
+
else {
|
12008
|
+
return null; // invalid
|
12009
|
+
}
|
12034
12010
|
}
|
12035
12011
|
|
12036
|
-
|
12037
|
-
t.getEventCache = function() {
|
12038
|
-
return cache;
|
12039
|
-
};
|
12040
|
-
|
12041
|
-
}
|
12042
|
-
|
12043
|
-
|
12044
|
-
// hook for external libs to manipulate event properties upon creation.
|
12045
|
-
// should manipulate the event in-place.
|
12046
|
-
Calendar.prototype.normalizeEvent = function(event) {
|
12047
|
-
};
|
12048
|
-
|
12049
|
-
|
12050
|
-
// Does the given span (start, end, and other location information)
|
12051
|
-
// fully contain the other?
|
12052
|
-
Calendar.prototype.spanContainsSpan = function(outerSpan, innerSpan) {
|
12053
|
-
var eventStart = outerSpan.start.clone().stripZone();
|
12054
|
-
var eventEnd = this.getEventEnd(outerSpan).stripZone();
|
12055
|
-
|
12056
|
-
return innerSpan.start >= eventStart && innerSpan.end <= eventEnd;
|
12012
|
+
return this.clientEvents(constraintInput); // probably an ID
|
12057
12013
|
};
|
12058
12014
|
|
12059
12015
|
|
12060
|
-
//
|
12061
|
-
//
|
12062
|
-
Calendar.prototype.
|
12063
|
-
var
|
12064
|
-
var
|
12065
|
-
var i, otherEvent;
|
12066
|
-
|
12067
|
-
for (i = 0; i < cache.length; i++) {
|
12068
|
-
otherEvent = cache[i];
|
12069
|
-
if (
|
12070
|
-
!event ||
|
12071
|
-
event._id !== otherEvent._id // don't compare the event to itself or other related [repeating] events
|
12072
|
-
) {
|
12073
|
-
peerEvents.push(otherEvent);
|
12074
|
-
}
|
12075
|
-
}
|
12016
|
+
// Does the event's date range intersect with the given range?
|
12017
|
+
// start/end already assumed to have stripped zones :(
|
12018
|
+
Calendar.prototype.eventIntersectsRange = function(event, range) {
|
12019
|
+
var eventStart = event.start.clone().stripZone();
|
12020
|
+
var eventEnd = this.getEventEnd(event).stripZone();
|
12076
12021
|
|
12077
|
-
return
|
12022
|
+
return range.start < eventEnd && range.end > eventStart;
|
12078
12023
|
};
|
12079
12024
|
|
12080
12025
|
|
12081
|
-
// updates the "backup" properties, which are preserved in order to compute diffs later on.
|
12082
|
-
function backupEventDates(event) {
|
12083
|
-
event._allDay = event.allDay;
|
12084
|
-
event._start = event.start.clone();
|
12085
|
-
event._end = event.end ? event.end.clone() : null;
|
12086
|
-
}
|
12087
|
-
|
12088
|
-
|
12089
12026
|
/* Business Hours
|
12090
12027
|
-----------------------------------------------------------------------------------------*/
|
12091
12028
|
|
@@ -12170,7 +12107,8 @@ var BasicView = FC.BasicView = View.extend({
|
|
12170
12107
|
dayGrid: null, // the main subcomponent that does most of the heavy lifting
|
12171
12108
|
|
12172
12109
|
dayNumbersVisible: false, // display day numbers on each day cell?
|
12173
|
-
|
12110
|
+
colWeekNumbersVisible: false, // display week numbers along the side?
|
12111
|
+
cellWeekNumbersVisible: false, // display week numbers in day cell?
|
12174
12112
|
|
12175
12113
|
weekNumberWidth: null, // width of all the week-number cells running down the side
|
12176
12114
|
|
@@ -12231,8 +12169,18 @@ var BasicView = FC.BasicView = View.extend({
|
|
12231
12169
|
renderDates: function() {
|
12232
12170
|
|
12233
12171
|
this.dayNumbersVisible = this.dayGrid.rowCnt > 1; // TODO: make grid responsible
|
12234
|
-
|
12235
|
-
|
12172
|
+
if (this.opt('weekNumbers')) {
|
12173
|
+
if (this.opt('weekNumbersWithinDays')) {
|
12174
|
+
this.cellWeekNumbersVisible = true;
|
12175
|
+
this.colWeekNumbersVisible = false;
|
12176
|
+
}
|
12177
|
+
else {
|
12178
|
+
this.cellWeekNumbersVisible = false;
|
12179
|
+
this.colWeekNumbersVisible = true;
|
12180
|
+
};
|
12181
|
+
}
|
12182
|
+
this.dayGrid.numbersVisible = this.dayNumbersVisible ||
|
12183
|
+
this.cellWeekNumbersVisible || this.colWeekNumbersVisible;
|
12236
12184
|
|
12237
12185
|
this.el.addClass('fc-basic-view').html(this.renderSkeletonHtml());
|
12238
12186
|
this.renderHead();
|
@@ -12316,7 +12264,7 @@ var BasicView = FC.BasicView = View.extend({
|
|
12316
12264
|
|
12317
12265
|
// Refreshes the horizontal dimensions of the view
|
12318
12266
|
updateWidth: function() {
|
12319
|
-
if (this.
|
12267
|
+
if (this.colWeekNumbersVisible) {
|
12320
12268
|
// Make sure all week number cells running down the side have the same width.
|
12321
12269
|
// Record the width for cells created later.
|
12322
12270
|
this.weekNumberWidth = matchCellWidths(
|
@@ -12457,9 +12405,8 @@ var BasicView = FC.BasicView = View.extend({
|
|
12457
12405
|
unrenderEvents: function() {
|
12458
12406
|
this.dayGrid.unrenderEvents();
|
12459
12407
|
|
12460
|
-
// we DON'T need to call updateHeight() because
|
12461
|
-
//
|
12462
|
-
// B) in IE8, this causes a flash whenever events are rerendered
|
12408
|
+
// we DON'T need to call updateHeight() because
|
12409
|
+
// a renderEvents() call always happens after this, which will eventually call updateHeight()
|
12463
12410
|
},
|
12464
12411
|
|
12465
12412
|
|
@@ -12504,7 +12451,7 @@ var basicDayGridMethods = {
|
|
12504
12451
|
renderHeadIntroHtml: function() {
|
12505
12452
|
var view = this.view;
|
12506
12453
|
|
12507
|
-
if (view.
|
12454
|
+
if (view.colWeekNumbersVisible) {
|
12508
12455
|
return '' +
|
12509
12456
|
'<th class="fc-week-number ' + view.widgetHeaderClass + '" ' + view.weekNumberStyleAttr() + '>' +
|
12510
12457
|
'<span>' + // needed for matchCellWidths
|
@@ -12520,13 +12467,15 @@ var basicDayGridMethods = {
|
|
12520
12467
|
// Generates the HTML that will go before content-skeleton cells that display the day/week numbers
|
12521
12468
|
renderNumberIntroHtml: function(row) {
|
12522
12469
|
var view = this.view;
|
12470
|
+
var weekStart = this.getCellDate(row, 0);
|
12523
12471
|
|
12524
|
-
if (view.
|
12472
|
+
if (view.colWeekNumbersVisible) {
|
12525
12473
|
return '' +
|
12526
12474
|
'<td class="fc-week-number" ' + view.weekNumberStyleAttr() + '>' +
|
12527
|
-
|
12528
|
-
|
12529
|
-
|
12475
|
+
view.buildGotoAnchorHtml( // aside from link, important for matchCellWidths
|
12476
|
+
{ date: weekStart, type: 'week', forceOff: this.colCnt === 1 },
|
12477
|
+
weekStart.format('w') // inner HTML
|
12478
|
+
) +
|
12530
12479
|
'</td>';
|
12531
12480
|
}
|
12532
12481
|
|
@@ -12538,7 +12487,7 @@ var basicDayGridMethods = {
|
|
12538
12487
|
renderBgIntroHtml: function() {
|
12539
12488
|
var view = this.view;
|
12540
12489
|
|
12541
|
-
if (view.
|
12490
|
+
if (view.colWeekNumbersVisible) {
|
12542
12491
|
return '<td class="fc-week-number ' + view.widgetContentClass + '" ' +
|
12543
12492
|
view.weekNumberStyleAttr() + '></td>';
|
12544
12493
|
}
|
@@ -12552,7 +12501,7 @@ var basicDayGridMethods = {
|
|
12552
12501
|
renderIntroHtml: function() {
|
12553
12502
|
var view = this.view;
|
12554
12503
|
|
12555
|
-
if (view.
|
12504
|
+
if (view.colWeekNumbersVisible) {
|
12556
12505
|
return '<td class="fc-week-number" ' + view.weekNumberStyleAttr() + '></td>';
|
12557
12506
|
}
|
12558
12507
|
|
@@ -12586,8 +12535,6 @@ var MonthView = FC.MonthView = BasicView.extend({
|
|
12586
12535
|
// Overrides the default BasicView behavior to have special multi-week auto-height logic
|
12587
12536
|
setGridHeight: function(height, isAuto) {
|
12588
12537
|
|
12589
|
-
isAuto = isAuto || this.opt('weekMode') === 'variable'; // LEGACY: weekMode is deprecated
|
12590
|
-
|
12591
12538
|
// if auto, make the height of each row the height that it would be if there were 6 weeks
|
12592
12539
|
if (isAuto) {
|
12593
12540
|
height *= this.rowCnt / 6;
|
@@ -12598,11 +12545,6 @@ var MonthView = FC.MonthView = BasicView.extend({
|
|
12598
12545
|
|
12599
12546
|
|
12600
12547
|
isFixedWeeks: function() {
|
12601
|
-
var weekMode = this.opt('weekMode'); // LEGACY: weekMode is deprecated
|
12602
|
-
if (weekMode) {
|
12603
|
-
return weekMode === 'fixed'; // if any other type of weekMode, assume NOT fixed
|
12604
|
-
}
|
12605
|
-
|
12606
12548
|
return this.opt('fixedWeekCount');
|
12607
12549
|
}
|
12608
12550
|
|
@@ -13032,9 +12974,8 @@ var AgendaView = FC.AgendaView = View.extend({
|
|
13032
12974
|
this.dayGrid.unrenderEvents();
|
13033
12975
|
}
|
13034
12976
|
|
13035
|
-
// we DON'T need to call updateHeight() because
|
13036
|
-
//
|
13037
|
-
// B) in IE8, this causes a flash whenever events are rerendered
|
12977
|
+
// we DON'T need to call updateHeight() because
|
12978
|
+
// a renderEvents() call always happens after this, which will eventually call updateHeight()
|
13038
12979
|
},
|
13039
12980
|
|
13040
12981
|
|
@@ -13102,9 +13043,10 @@ var agendaTimeGridMethods = {
|
|
13102
13043
|
|
13103
13044
|
return '' +
|
13104
13045
|
'<th class="fc-axis fc-week-number ' + view.widgetHeaderClass + '" ' + view.axisStyleAttr() + '>' +
|
13105
|
-
|
13106
|
-
|
13107
|
-
|
13046
|
+
view.buildGotoAnchorHtml( // aside from link, important for matchCellWidths
|
13047
|
+
{ date: this.start, type: 'week', forceOff: this.colCnt > 1 },
|
13048
|
+
htmlEscape(weekText) // inner HTML
|
13049
|
+
) +
|
13108
13050
|
'</th>';
|
13109
13051
|
}
|
13110
13052
|
else {
|
@@ -13143,7 +13085,7 @@ var agendaDayGridMethods = {
|
|
13143
13085
|
return '' +
|
13144
13086
|
'<td class="fc-axis ' + view.widgetContentClass + '" ' + view.axisStyleAttr() + '>' +
|
13145
13087
|
'<span>' + // needed for matchCellWidths
|
13146
|
-
|
13088
|
+
view.getAllDayHtml() +
|
13147
13089
|
'</span>' +
|
13148
13090
|
'</td>';
|
13149
13091
|
},
|
@@ -13177,7 +13119,6 @@ fcViews.agenda = {
|
|
13177
13119
|
'class': AgendaView,
|
13178
13120
|
defaults: {
|
13179
13121
|
allDaySlot: true,
|
13180
|
-
allDayText: 'all-day',
|
13181
13122
|
slotDuration: '00:30:00',
|
13182
13123
|
minTime: '00:00:00',
|
13183
13124
|
maxTime: '24:00:00',
|
@@ -13195,6 +13136,294 @@ fcViews.agendaWeek = {
|
|
13195
13136
|
duration: { weeks: 1 }
|
13196
13137
|
};
|
13197
13138
|
;;
|
13139
|
+
|
13140
|
+
/*
|
13141
|
+
Responsible for the scroller, and forwarding event-related actions into the "grid"
|
13142
|
+
*/
|
13143
|
+
var ListView = View.extend({
|
13144
|
+
|
13145
|
+
grid: null,
|
13146
|
+
scroller: null,
|
13147
|
+
|
13148
|
+
initialize: function() {
|
13149
|
+
this.grid = new ListViewGrid(this);
|
13150
|
+
this.scroller = new Scroller({
|
13151
|
+
overflowX: 'hidden',
|
13152
|
+
overflowY: 'auto'
|
13153
|
+
});
|
13154
|
+
},
|
13155
|
+
|
13156
|
+
setRange: function(range) {
|
13157
|
+
View.prototype.setRange.call(this, range); // super
|
13158
|
+
|
13159
|
+
this.grid.setRange(range); // needs to process range-related options
|
13160
|
+
},
|
13161
|
+
|
13162
|
+
renderSkeleton: function() {
|
13163
|
+
this.el.addClass(
|
13164
|
+
'fc-list-view ' +
|
13165
|
+
this.widgetContentClass
|
13166
|
+
);
|
13167
|
+
|
13168
|
+
this.scroller.render();
|
13169
|
+
this.scroller.el.appendTo(this.el);
|
13170
|
+
|
13171
|
+
this.grid.setElement(this.scroller.scrollEl);
|
13172
|
+
},
|
13173
|
+
|
13174
|
+
unrenderSkeleton: function() {
|
13175
|
+
this.scroller.destroy(); // will remove the Grid too
|
13176
|
+
},
|
13177
|
+
|
13178
|
+
setHeight: function(totalHeight, isAuto) {
|
13179
|
+
this.scroller.setHeight(this.computeScrollerHeight(totalHeight));
|
13180
|
+
},
|
13181
|
+
|
13182
|
+
computeScrollerHeight: function(totalHeight) {
|
13183
|
+
return totalHeight -
|
13184
|
+
subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller
|
13185
|
+
},
|
13186
|
+
|
13187
|
+
renderEvents: function(events) {
|
13188
|
+
this.grid.renderEvents(events);
|
13189
|
+
},
|
13190
|
+
|
13191
|
+
unrenderEvents: function() {
|
13192
|
+
this.grid.unrenderEvents();
|
13193
|
+
},
|
13194
|
+
|
13195
|
+
isEventResizable: function(event) {
|
13196
|
+
return false;
|
13197
|
+
},
|
13198
|
+
|
13199
|
+
isEventDraggable: function(event) {
|
13200
|
+
return false;
|
13201
|
+
}
|
13202
|
+
|
13203
|
+
});
|
13204
|
+
|
13205
|
+
/*
|
13206
|
+
Responsible for event rendering and user-interaction.
|
13207
|
+
Its "el" is the inner-content of the above view's scroller.
|
13208
|
+
*/
|
13209
|
+
var ListViewGrid = Grid.extend({
|
13210
|
+
|
13211
|
+
segSelector: '.fc-list-item', // which elements accept event actions
|
13212
|
+
hasDayInteractions: false, // no day selection or day clicking
|
13213
|
+
|
13214
|
+
// slices by day
|
13215
|
+
spanToSegs: function(span) {
|
13216
|
+
var view = this.view;
|
13217
|
+
var dayStart = view.start.clone();
|
13218
|
+
var dayEnd;
|
13219
|
+
var seg;
|
13220
|
+
var segs = [];
|
13221
|
+
|
13222
|
+
while (dayStart < view.end) {
|
13223
|
+
dayEnd = dayStart.clone().add(1, 'day');
|
13224
|
+
seg = intersectRanges(span, {
|
13225
|
+
start: dayStart,
|
13226
|
+
end: dayEnd
|
13227
|
+
});
|
13228
|
+
if (seg) {
|
13229
|
+
segs.push(seg);
|
13230
|
+
}
|
13231
|
+
dayStart = dayEnd;
|
13232
|
+
}
|
13233
|
+
|
13234
|
+
return segs;
|
13235
|
+
},
|
13236
|
+
|
13237
|
+
// like "4:00am"
|
13238
|
+
computeEventTimeFormat: function() {
|
13239
|
+
return this.view.opt('mediumTimeFormat');
|
13240
|
+
},
|
13241
|
+
|
13242
|
+
// for events with a url, the whole <tr> should be clickable,
|
13243
|
+
// but it's impossible to wrap with an <a> tag. simulate this.
|
13244
|
+
handleSegClick: function(seg, ev) {
|
13245
|
+
var url;
|
13246
|
+
|
13247
|
+
Grid.prototype.handleSegClick.apply(this, arguments); // super. might prevent the default action
|
13248
|
+
|
13249
|
+
// not clicking on or within an <a> with an href
|
13250
|
+
if (!$(ev.target).closest('a[href]').length) {
|
13251
|
+
url = seg.event.url;
|
13252
|
+
if (url && !ev.isDefaultPrevented()) { // jsEvent not cancelled in handler
|
13253
|
+
window.location.href = url; // simulate link click
|
13254
|
+
}
|
13255
|
+
}
|
13256
|
+
},
|
13257
|
+
|
13258
|
+
// returns list of foreground segs that were actually rendered
|
13259
|
+
renderFgSegs: function(segs) {
|
13260
|
+
segs = this.renderFgSegEls(segs); // might filter away hidden events
|
13261
|
+
|
13262
|
+
if (!segs.length) {
|
13263
|
+
this.renderEmptyMessage();
|
13264
|
+
return segs;
|
13265
|
+
}
|
13266
|
+
else {
|
13267
|
+
return this.renderSegList(segs);
|
13268
|
+
}
|
13269
|
+
},
|
13270
|
+
|
13271
|
+
renderEmptyMessage: function() {
|
13272
|
+
this.el.html(
|
13273
|
+
'<div class="fc-list-empty-wrap2">' + // TODO: try less wraps
|
13274
|
+
'<div class="fc-list-empty-wrap1">' +
|
13275
|
+
'<div class="fc-list-empty">' +
|
13276
|
+
htmlEscape(this.view.opt('noEventsMessage')) +
|
13277
|
+
'</div>' +
|
13278
|
+
'</div>' +
|
13279
|
+
'</div>'
|
13280
|
+
);
|
13281
|
+
},
|
13282
|
+
|
13283
|
+
// render the event segments in the view. returns the mutated array.
|
13284
|
+
renderSegList: function(segs) {
|
13285
|
+
var tableEl = $('<table class="fc-list-table"><tbody/></table>');
|
13286
|
+
var tbodyEl = tableEl.find('tbody');
|
13287
|
+
var i, seg;
|
13288
|
+
var dayDate;
|
13289
|
+
|
13290
|
+
this.sortEventSegs(segs);
|
13291
|
+
|
13292
|
+
for (i = 0; i < segs.length; i++) {
|
13293
|
+
seg = segs[i];
|
13294
|
+
|
13295
|
+
// append a day header
|
13296
|
+
if (!dayDate || !seg.start.isSame(dayDate, 'day')) {
|
13297
|
+
dayDate = seg.start.clone().stripTime();
|
13298
|
+
tbodyEl.append(this.dayHeaderHtml(dayDate));
|
13299
|
+
}
|
13300
|
+
|
13301
|
+
tbodyEl.append(seg.el); // append event row
|
13302
|
+
}
|
13303
|
+
|
13304
|
+
this.el.empty().append(tableEl);
|
13305
|
+
|
13306
|
+
return segs; // return the sorted list
|
13307
|
+
},
|
13308
|
+
|
13309
|
+
// generates the HTML for the day headers that live amongst the event rows
|
13310
|
+
dayHeaderHtml: function(dayDate) {
|
13311
|
+
var view = this.view;
|
13312
|
+
var mainFormat = view.opt('listDayFormat');
|
13313
|
+
var altFormat = view.opt('listDayAltFormat');
|
13314
|
+
|
13315
|
+
return '<tr class="fc-list-heading" data-date="' + dayDate.format('YYYY-MM-DD') + '">' +
|
13316
|
+
'<td class="' + view.widgetHeaderClass + '" colspan="3">' +
|
13317
|
+
(mainFormat ?
|
13318
|
+
view.buildGotoAnchorHtml(
|
13319
|
+
dayDate,
|
13320
|
+
{ 'class': 'fc-list-heading-main' },
|
13321
|
+
htmlEscape(dayDate.format(mainFormat)) // inner HTML
|
13322
|
+
) :
|
13323
|
+
'') +
|
13324
|
+
(altFormat ?
|
13325
|
+
view.buildGotoAnchorHtml(
|
13326
|
+
dayDate,
|
13327
|
+
{ 'class': 'fc-list-heading-alt' },
|
13328
|
+
htmlEscape(dayDate.format(altFormat)) // inner HTML
|
13329
|
+
) :
|
13330
|
+
'') +
|
13331
|
+
'</td>' +
|
13332
|
+
'</tr>';
|
13333
|
+
},
|
13334
|
+
|
13335
|
+
// generates the HTML for a single event row
|
13336
|
+
fgSegHtml: function(seg) {
|
13337
|
+
var view = this.view;
|
13338
|
+
var classes = [ 'fc-list-item' ].concat(this.getSegCustomClasses(seg));
|
13339
|
+
var bgColor = this.getSegBackgroundColor(seg);
|
13340
|
+
var event = seg.event;
|
13341
|
+
var url = event.url;
|
13342
|
+
var timeHtml;
|
13343
|
+
|
13344
|
+
if (!seg.start.hasTime()) {
|
13345
|
+
if (this.displayEventTime) {
|
13346
|
+
timeHtml = view.getAllDayHtml();
|
13347
|
+
}
|
13348
|
+
}
|
13349
|
+
else {
|
13350
|
+
timeHtml = htmlEscape(this.getEventTimeText(event)); // might return empty
|
13351
|
+
}
|
13352
|
+
|
13353
|
+
if (url) {
|
13354
|
+
classes.push('fc-has-url');
|
13355
|
+
}
|
13356
|
+
|
13357
|
+
return '<tr class="' + classes.join(' ') + '">' +
|
13358
|
+
(timeHtml ?
|
13359
|
+
'<td class="fc-list-item-time ' + view.widgetContentClass + '">' +
|
13360
|
+
timeHtml +
|
13361
|
+
'</td>' :
|
13362
|
+
'') +
|
13363
|
+
'<td class="fc-list-item-marker ' + view.widgetContentClass + '">' +
|
13364
|
+
'<span class="fc-event-dot"' +
|
13365
|
+
(bgColor ?
|
13366
|
+
' style="background-color:' + bgColor + '"' :
|
13367
|
+
'') +
|
13368
|
+
'></span>' +
|
13369
|
+
'</td>' +
|
13370
|
+
'<td class="fc-list-item-title ' + view.widgetContentClass + '">' +
|
13371
|
+
'<a' + (url ? ' href="' + htmlEscape(url) + '"' : '') + '>' +
|
13372
|
+
htmlEscape(seg.event.title) +
|
13373
|
+
'</a>' +
|
13374
|
+
'</td>' +
|
13375
|
+
'</tr>';
|
13376
|
+
}
|
13377
|
+
|
13378
|
+
});
|
13379
|
+
|
13380
|
+
;;
|
13381
|
+
|
13382
|
+
fcViews.list = {
|
13383
|
+
'class': ListView,
|
13384
|
+
buttonTextKey: 'list', // what to lookup in locale files
|
13385
|
+
defaults: {
|
13386
|
+
buttonText: 'list', // text to display for English
|
13387
|
+
listTime: true, // show the time column?
|
13388
|
+
listDayFormat: 'LL', // like "January 1, 2016"
|
13389
|
+
noEventsMessage: 'No events to display'
|
13390
|
+
}
|
13391
|
+
};
|
13392
|
+
|
13393
|
+
fcViews.listDay = {
|
13394
|
+
type: 'list',
|
13395
|
+
duration: { days: 1 },
|
13396
|
+
defaults: {
|
13397
|
+
listDayFormat: 'dddd' // day-of-week is all we need. full date is probably in header
|
13398
|
+
}
|
13399
|
+
};
|
13400
|
+
|
13401
|
+
fcViews.listWeek = {
|
13402
|
+
type: 'list',
|
13403
|
+
duration: { weeks: 1 },
|
13404
|
+
defaults: {
|
13405
|
+
listDayFormat: 'dddd', // day-of-week is more important
|
13406
|
+
listDayAltFormat: 'LL'
|
13407
|
+
}
|
13408
|
+
};
|
13409
|
+
|
13410
|
+
fcViews.listMonth = {
|
13411
|
+
type: 'list',
|
13412
|
+
duration: { month: 1 },
|
13413
|
+
defaults: {
|
13414
|
+
listDayAltFormat: 'dddd' // day-of-week is nice-to-have
|
13415
|
+
}
|
13416
|
+
};
|
13417
|
+
|
13418
|
+
fcViews.listYear = {
|
13419
|
+
type: 'list',
|
13420
|
+
duration: { year: 1 },
|
13421
|
+
defaults: {
|
13422
|
+
listDayAltFormat: 'dddd' // day-of-week is nice-to-have
|
13423
|
+
}
|
13424
|
+
};
|
13425
|
+
|
13426
|
+
;;
|
13198
13427
|
|
13199
13428
|
return FC; // export for Node/CommonJS
|
13200
13429
|
});
|