fullcalendar.io-rails 3.3.1 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fullcalendar.io/rails/version.rb +1 -1
- data/vendor/assets/javascripts/fullcalendar.js +1707 -1407
- data/vendor/assets/javascripts/fullcalendar/gcal.js +3 -3
- data/vendor/assets/javascripts/fullcalendar/locale-all.js +5 -5
- data/vendor/assets/javascripts/fullcalendar/locale/af.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ar-dz.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ar-kw.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/ar-ly.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ar-ma.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ar-sa.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ar-tn.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ar.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/bg.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ca.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/cs.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/da.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/de-at.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/de-ch.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/de.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/el.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/en-au.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/en-ca.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/en-gb.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/en-ie.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/en-nz.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/es-do.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/es.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/et.js +1 -0
- data/vendor/assets/javascripts/fullcalendar/locale/eu.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/fa.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/fi.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/fr-ca.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/fr-ch.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/fr.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/gl.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/he.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/hi.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/hr.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/hu.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/id.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/is.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/it.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ja.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/kk.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ko.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/lb.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/lt.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/lv.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/mk.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ms-my.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ms.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/nb.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/nl-be.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/nl.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/nn.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/pl.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/pt-br.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/pt.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ro.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/ru.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/sk.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/sl.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/sr-cyrl.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/sr.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/sv.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/th.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/tr.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/uk.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/vi.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/zh-cn.js +1 -1
- data/vendor/assets/javascripts/fullcalendar/locale/zh-tw.js +1 -1
- data/vendor/assets/stylesheets/fullcalendar.css +1 -1
- data/vendor/assets/stylesheets/fullcalendar.print.css +1 -1
- metadata +101 -156
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b02874e67890f4d0b6f1992597ecead7235953ff
|
4
|
+
data.tar.gz: 6afc0a25ade54f6389f810f86833ba26067be68b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 030d51c3449b814cf150dab1c0d96b8124515317252a3c9cef5a4c2f1325ed7cc37e88281aa71e9452eae3883172e7c7ec9d7d3c22894195711cb1eed89deecc
|
7
|
+
data.tar.gz: 90b2d739fc26cd1d7fc5fd3fa2170c62ec63fe6942e3a7cc2db766e0f39ac11f931fb35a4e2364545ab4d56140d9119c29208769bf25cfa0cf5abe085e910604
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* FullCalendar v3.
|
2
|
+
* FullCalendar v3.4.0
|
3
3
|
* Docs & License: https://fullcalendar.io/
|
4
4
|
* (c) 2017 Adam Shaw
|
5
5
|
*/
|
@@ -19,7 +19,7 @@
|
|
19
19
|
;;
|
20
20
|
|
21
21
|
var FC = $.fullCalendar = {
|
22
|
-
version: "3.
|
22
|
+
version: "3.4.0",
|
23
23
|
// When introducing internal API incompatibilities (where fullcalendar plugins would break),
|
24
24
|
// the minor version of the calendar should be upped (ex: 2.7.2 -> 2.8.0)
|
25
25
|
// and the below integer should be incremented.
|
@@ -1402,28 +1402,48 @@ newMomentProto.utcOffset = function(tzo) {
|
|
1402
1402
|
// -------------------------------------------------------------------------------------------------
|
1403
1403
|
|
1404
1404
|
newMomentProto.format = function() {
|
1405
|
+
|
1405
1406
|
if (this._fullCalendar && arguments[0]) { // an enhanced moment? and a format string provided?
|
1406
1407
|
return formatDate(this, arguments[0]); // our extended formatting
|
1407
1408
|
}
|
1408
1409
|
if (this._ambigTime) {
|
1409
|
-
return oldMomentFormat(this, 'YYYY-MM-DD');
|
1410
|
+
return oldMomentFormat(englishMoment(this), 'YYYY-MM-DD');
|
1410
1411
|
}
|
1411
1412
|
if (this._ambigZone) {
|
1412
|
-
return oldMomentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
|
1413
|
+
return oldMomentFormat(englishMoment(this), 'YYYY-MM-DD[T]HH:mm:ss');
|
1414
|
+
}
|
1415
|
+
if (this._fullCalendar) { // enhanced non-ambig moment?
|
1416
|
+
// moment.format() doesn't ensure english, but we want to.
|
1417
|
+
return oldMomentFormat(englishMoment(this));
|
1413
1418
|
}
|
1419
|
+
|
1414
1420
|
return oldMomentProto.format.apply(this, arguments);
|
1415
1421
|
};
|
1416
1422
|
|
1417
1423
|
newMomentProto.toISOString = function() {
|
1424
|
+
|
1418
1425
|
if (this._ambigTime) {
|
1419
|
-
return oldMomentFormat(this, 'YYYY-MM-DD');
|
1426
|
+
return oldMomentFormat(englishMoment(this), 'YYYY-MM-DD');
|
1420
1427
|
}
|
1421
1428
|
if (this._ambigZone) {
|
1422
|
-
return oldMomentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
|
1429
|
+
return oldMomentFormat(englishMoment(this), 'YYYY-MM-DD[T]HH:mm:ss');
|
1423
1430
|
}
|
1431
|
+
if (this._fullCalendar) { // enhanced non-ambig moment?
|
1432
|
+
// depending on browser, moment might not output english. ensure english.
|
1433
|
+
// https://github.com/moment/moment/blob/2.18.1/src/lib/moment/format.js#L22
|
1434
|
+
return oldMomentProto.toISOString.apply(englishMoment(this), arguments);
|
1435
|
+
}
|
1436
|
+
|
1424
1437
|
return oldMomentProto.toISOString.apply(this, arguments);
|
1425
1438
|
};
|
1426
1439
|
|
1440
|
+
function englishMoment(mom) {
|
1441
|
+
if (mom.locale() !== 'en') {
|
1442
|
+
return mom.clone().locale('en');
|
1443
|
+
}
|
1444
|
+
return mom;
|
1445
|
+
}
|
1446
|
+
|
1427
1447
|
;;
|
1428
1448
|
(function() {
|
1429
1449
|
|
@@ -1906,293 +1926,742 @@ function mixIntoClass(theClass, members) {
|
|
1906
1926
|
}
|
1907
1927
|
;;
|
1908
1928
|
|
1909
|
-
|
1910
|
-
Wrap jQuery's Deferred Promise object to be slightly more Promise/A+ compliant.
|
1911
|
-
With the added non-standard feature of synchronously executing handlers on resolved promises,
|
1912
|
-
which doesn't always happen otherwise (esp with nested .then handlers!?),
|
1913
|
-
so, this makes things a lot easier, esp because jQuery 3 changed the synchronicity for Deferred objects.
|
1929
|
+
var Model = Class.extend(EmitterMixin, ListenerMixin, {
|
1914
1930
|
|
1915
|
-
|
1916
|
-
|
1931
|
+
_props: null,
|
1932
|
+
_watchers: null,
|
1933
|
+
_globalWatchArgs: null,
|
1917
1934
|
|
1918
|
-
function
|
1919
|
-
|
1920
|
-
|
1935
|
+
constructor: function() {
|
1936
|
+
this._watchers = {};
|
1937
|
+
this._props = {};
|
1938
|
+
this.applyGlobalWatchers();
|
1939
|
+
},
|
1921
1940
|
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1941
|
+
applyGlobalWatchers: function() {
|
1942
|
+
var argSets = this._globalWatchArgs || [];
|
1943
|
+
var i;
|
1944
|
+
|
1945
|
+
for (i = 0; i < argSets.length; i++) {
|
1946
|
+
this.watch.apply(this, argSets[i]);
|
1947
|
+
}
|
1948
|
+
},
|
1949
|
+
|
1950
|
+
has: function(name) {
|
1951
|
+
return name in this._props;
|
1952
|
+
},
|
1953
|
+
|
1954
|
+
get: function(name) {
|
1955
|
+
if (name === undefined) {
|
1956
|
+
return this._props;
|
1957
|
+
}
|
1958
|
+
|
1959
|
+
return this._props[name];
|
1960
|
+
},
|
1961
|
+
|
1962
|
+
set: function(name, val) {
|
1963
|
+
var newProps;
|
1964
|
+
|
1965
|
+
if (typeof name === 'string') {
|
1966
|
+
newProps = {};
|
1967
|
+
newProps[name] = val === undefined ? null : val;
|
1968
|
+
}
|
1969
|
+
else {
|
1970
|
+
newProps = name;
|
1971
|
+
}
|
1972
|
+
|
1973
|
+
this.setProps(newProps);
|
1974
|
+
},
|
1975
|
+
|
1976
|
+
reset: function(newProps) {
|
1977
|
+
var oldProps = this._props;
|
1978
|
+
var changeset = {}; // will have undefined's to signal unsets
|
1979
|
+
var name;
|
1980
|
+
|
1981
|
+
for (name in oldProps) {
|
1982
|
+
changeset[name] = undefined;
|
1983
|
+
}
|
1984
|
+
|
1985
|
+
for (name in newProps) {
|
1986
|
+
changeset[name] = newProps[name];
|
1987
|
+
}
|
1988
|
+
|
1989
|
+
this.setProps(changeset);
|
1990
|
+
},
|
1991
|
+
|
1992
|
+
unset: function(name) { // accepts a string or array of strings
|
1993
|
+
var newProps = {};
|
1994
|
+
var names;
|
1995
|
+
var i;
|
1996
|
+
|
1997
|
+
if (typeof name === 'string') {
|
1998
|
+
names = [ name ];
|
1999
|
+
}
|
2000
|
+
else {
|
2001
|
+
names = name;
|
2002
|
+
}
|
2003
|
+
|
2004
|
+
for (i = 0; i < names.length; i++) {
|
2005
|
+
newProps[names[i]] = undefined;
|
2006
|
+
}
|
2007
|
+
|
2008
|
+
this.setProps(newProps);
|
2009
|
+
},
|
2010
|
+
|
2011
|
+
setProps: function(newProps) {
|
2012
|
+
var changedProps = {};
|
2013
|
+
var changedCnt = 0;
|
2014
|
+
var name, val;
|
2015
|
+
|
2016
|
+
for (name in newProps) {
|
2017
|
+
val = newProps[name];
|
2018
|
+
|
2019
|
+
// a change in value?
|
2020
|
+
// if an object, don't check equality, because might have been mutated internally.
|
2021
|
+
// TODO: eventually enforce immutability.
|
2022
|
+
if (
|
2023
|
+
typeof val === 'object' ||
|
2024
|
+
val !== this._props[name]
|
2025
|
+
) {
|
2026
|
+
changedProps[name] = val;
|
2027
|
+
changedCnt++;
|
1932
2028
|
}
|
1933
|
-
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1937
|
-
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
2029
|
+
}
|
2030
|
+
|
2031
|
+
if (changedCnt) {
|
2032
|
+
|
2033
|
+
this.trigger('before:batchChange', changedProps);
|
2034
|
+
|
2035
|
+
for (name in changedProps) {
|
2036
|
+
val = changedProps[name];
|
2037
|
+
|
2038
|
+
this.trigger('before:change', name, val);
|
2039
|
+
this.trigger('before:change:' + name, val);
|
2040
|
+
}
|
2041
|
+
|
2042
|
+
for (name in changedProps) {
|
2043
|
+
val = changedProps[name];
|
2044
|
+
|
2045
|
+
if (val === undefined) {
|
2046
|
+
delete this._props[name];
|
1945
2047
|
}
|
2048
|
+
else {
|
2049
|
+
this._props[name] = val;
|
2050
|
+
}
|
2051
|
+
|
2052
|
+
this.trigger('change:' + name, val);
|
2053
|
+
this.trigger('change', name, val);
|
2054
|
+
}
|
2055
|
+
|
2056
|
+
this.trigger('batchChange', changedProps);
|
2057
|
+
}
|
2058
|
+
},
|
2059
|
+
|
2060
|
+
watch: function(name, depList, startFunc, stopFunc) {
|
2061
|
+
var _this = this;
|
2062
|
+
|
2063
|
+
this.unwatch(name);
|
2064
|
+
|
2065
|
+
this._watchers[name] = this._watchDeps(depList, function(deps) {
|
2066
|
+
var res = startFunc.call(_this, deps);
|
2067
|
+
|
2068
|
+
if (res && res.then) {
|
2069
|
+
_this.unset(name); // put in an unset state while resolving
|
2070
|
+
res.then(function(val) {
|
2071
|
+
_this.set(name, val);
|
2072
|
+
});
|
2073
|
+
}
|
2074
|
+
else {
|
2075
|
+
_this.set(name, res);
|
2076
|
+
}
|
2077
|
+
}, function() {
|
2078
|
+
_this.unset(name);
|
2079
|
+
|
2080
|
+
if (stopFunc) {
|
2081
|
+
stopFunc.call(_this);
|
1946
2082
|
}
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1950
|
-
|
2083
|
+
});
|
2084
|
+
},
|
2085
|
+
|
2086
|
+
unwatch: function(name) {
|
2087
|
+
var watcher = this._watchers[name];
|
2088
|
+
|
2089
|
+
if (watcher) {
|
2090
|
+
delete this._watchers[name];
|
2091
|
+
watcher.teardown();
|
2092
|
+
}
|
2093
|
+
},
|
2094
|
+
|
2095
|
+
_watchDeps: function(depList, startFunc, stopFunc) {
|
2096
|
+
var _this = this;
|
2097
|
+
var queuedChangeCnt = 0;
|
2098
|
+
var depCnt = depList.length;
|
2099
|
+
var satisfyCnt = 0;
|
2100
|
+
var values = {}; // what's passed as the `deps` arguments
|
2101
|
+
var bindTuples = []; // array of [ eventName, handlerFunc ] arrays
|
2102
|
+
var isCallingStop = false;
|
2103
|
+
|
2104
|
+
function onBeforeDepChange(depName, val, isOptional) {
|
2105
|
+
queuedChangeCnt++;
|
2106
|
+
if (queuedChangeCnt === 1) { // first change to cause a "stop" ?
|
2107
|
+
if (satisfyCnt === depCnt) { // all deps previously satisfied?
|
2108
|
+
isCallingStop = true;
|
2109
|
+
stopFunc();
|
2110
|
+
isCallingStop = false;
|
1951
2111
|
}
|
1952
2112
|
}
|
2113
|
+
}
|
1953
2114
|
|
1954
|
-
|
1955
|
-
};
|
1956
|
-
}
|
2115
|
+
function onDepChange(depName, val, isOptional) {
|
1957
2116
|
|
1958
|
-
|
1959
|
-
}
|
2117
|
+
if (val === undefined) { // unsetting a value?
|
1960
2118
|
|
1961
|
-
|
2119
|
+
// required dependency that was previously set?
|
2120
|
+
if (!isOptional && values[depName] !== undefined) {
|
2121
|
+
satisfyCnt--;
|
2122
|
+
}
|
1962
2123
|
|
1963
|
-
|
2124
|
+
delete values[depName];
|
2125
|
+
}
|
2126
|
+
else { // setting a value?
|
1964
2127
|
|
2128
|
+
// required dependency that was previously unset?
|
2129
|
+
if (!isOptional && values[depName] === undefined) {
|
2130
|
+
satisfyCnt++;
|
2131
|
+
}
|
1965
2132
|
|
1966
|
-
|
1967
|
-
|
1968
|
-
return value.promise();
|
1969
|
-
}
|
1970
|
-
if (value && typeof value.then === 'function') {
|
1971
|
-
return value;
|
1972
|
-
}
|
1973
|
-
else {
|
1974
|
-
var deferred = $.Deferred().resolve(value);
|
1975
|
-
var promise = deferred.promise();
|
2133
|
+
values[depName] = val;
|
2134
|
+
}
|
1976
2135
|
|
1977
|
-
|
1978
|
-
|
2136
|
+
queuedChangeCnt--;
|
2137
|
+
if (!queuedChangeCnt) { // last change to cause a "start"?
|
1979
2138
|
|
1980
|
-
|
2139
|
+
// now finally satisfied or satisfied all along?
|
2140
|
+
if (satisfyCnt === depCnt) {
|
1981
2141
|
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
2142
|
+
// if the stopFunc initiated another value change, ignore it.
|
2143
|
+
// it will be processed by another change event anyway.
|
2144
|
+
if (!isCallingStop) {
|
2145
|
+
startFunc(values);
|
2146
|
+
}
|
1985
2147
|
}
|
1986
|
-
|
1987
|
-
};
|
2148
|
+
}
|
1988
2149
|
}
|
1989
2150
|
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
2151
|
+
// intercept for .on() that remembers handlers
|
2152
|
+
function bind(eventName, handler) {
|
2153
|
+
_this.on(eventName, handler);
|
2154
|
+
bindTuples.push([ eventName, handler ]);
|
2155
|
+
}
|
1993
2156
|
|
2157
|
+
// listen to dependency changes
|
2158
|
+
depList.forEach(function(depName) {
|
2159
|
+
var isOptional = false;
|
1994
2160
|
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
2161
|
+
if (depName.charAt(0) === '?') { // TODO: more DRY
|
2162
|
+
depName = depName.substring(1);
|
2163
|
+
isOptional = true;
|
2164
|
+
}
|
1998
2165
|
|
2166
|
+
bind('before:change:' + depName, function(val) {
|
2167
|
+
onBeforeDepChange(depName, val, isOptional);
|
2168
|
+
});
|
1999
2169
|
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2170
|
+
bind('change:' + depName, function(val) {
|
2171
|
+
onDepChange(depName, val, isOptional);
|
2172
|
+
});
|
2173
|
+
});
|
2004
2174
|
|
2005
|
-
|
2006
|
-
|
2007
|
-
|
2175
|
+
// process current dependency values
|
2176
|
+
depList.forEach(function(depName) {
|
2177
|
+
var isOptional = false;
|
2008
2178
|
|
2009
|
-
|
2010
|
-
|
2179
|
+
if (depName.charAt(0) === '?') { // TODO: more DRY
|
2180
|
+
depName = depName.substring(1);
|
2181
|
+
isOptional = true;
|
2182
|
+
}
|
2011
2183
|
|
2012
|
-
if (
|
2013
|
-
values.
|
2184
|
+
if (_this.has(depName)) {
|
2185
|
+
values[depName] = _this.get(depName);
|
2186
|
+
satisfyCnt++;
|
2014
2187
|
}
|
2015
|
-
else if (
|
2016
|
-
|
2017
|
-
break;
|
2188
|
+
else if (isOptional) {
|
2189
|
+
satisfyCnt++;
|
2018
2190
|
}
|
2019
|
-
|
2020
|
-
|
2191
|
+
});
|
2192
|
+
|
2193
|
+
// initially satisfied
|
2194
|
+
if (satisfyCnt === depCnt) {
|
2195
|
+
startFunc(values);
|
2196
|
+
}
|
2197
|
+
|
2198
|
+
return {
|
2199
|
+
teardown: function() {
|
2200
|
+
// remove all handlers
|
2201
|
+
for (var i = 0; i < bindTuples.length; i++) {
|
2202
|
+
_this.off(bindTuples[i][0], bindTuples[i][1]);
|
2203
|
+
}
|
2204
|
+
bindTuples = null;
|
2205
|
+
|
2206
|
+
// was satisfied, so call stopFunc
|
2207
|
+
if (satisfyCnt === depCnt) {
|
2208
|
+
stopFunc();
|
2209
|
+
}
|
2210
|
+
},
|
2211
|
+
flash: function() {
|
2212
|
+
if (satisfyCnt === depCnt) {
|
2213
|
+
stopFunc();
|
2214
|
+
startFunc(values);
|
2215
|
+
}
|
2021
2216
|
}
|
2217
|
+
};
|
2218
|
+
},
|
2219
|
+
|
2220
|
+
flash: function(name) {
|
2221
|
+
var watcher = this._watchers[name];
|
2222
|
+
|
2223
|
+
if (watcher) {
|
2224
|
+
watcher.flash();
|
2022
2225
|
}
|
2023
2226
|
}
|
2024
2227
|
|
2025
|
-
|
2026
|
-
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2031
|
-
|
2228
|
+
});
|
2229
|
+
|
2230
|
+
|
2231
|
+
Model.watch = function(/* same arguments as this.watch() */) {
|
2232
|
+
var proto = this.prototype;
|
2233
|
+
|
2234
|
+
if (!proto._globalWatchArgs) {
|
2235
|
+
proto._globalWatchArgs = [];
|
2032
2236
|
}
|
2237
|
+
|
2238
|
+
proto._globalWatchArgs.push(arguments);
|
2033
2239
|
};
|
2034
2240
|
|
2241
|
+
|
2242
|
+
FC.Model = Model;
|
2243
|
+
|
2244
|
+
|
2035
2245
|
;;
|
2036
2246
|
|
2037
|
-
|
2247
|
+
var Promise = {
|
2038
2248
|
|
2039
|
-
function
|
2040
|
-
|
2249
|
+
construct: function(executor) {
|
2250
|
+
var deferred = $.Deferred();
|
2251
|
+
var promise = deferred.promise();
|
2041
2252
|
|
2042
|
-
|
2043
|
-
|
2253
|
+
if (typeof executor === 'function') {
|
2254
|
+
executor(
|
2255
|
+
function(val) { // resolve
|
2256
|
+
deferred.resolve(val);
|
2257
|
+
attachImmediatelyResolvingThen(promise, val);
|
2258
|
+
},
|
2259
|
+
function() { // reject
|
2260
|
+
deferred.reject();
|
2261
|
+
attachImmediatelyRejectingThen(promise);
|
2262
|
+
}
|
2263
|
+
);
|
2264
|
+
}
|
2044
2265
|
|
2045
|
-
|
2046
|
-
|
2047
|
-
var runFunc = function() {
|
2048
|
-
Promise.resolve(taskFunc()) // result might be async, coerce to promise
|
2049
|
-
.then(resolve) // resolve TaskQueue::push's promise, for the caller. will receive result of taskFunc.
|
2050
|
-
.then(function() {
|
2051
|
-
q.shift(); // pop itself off
|
2266
|
+
return promise;
|
2267
|
+
},
|
2052
2268
|
|
2053
|
-
|
2054
|
-
|
2055
|
-
|
2056
|
-
}
|
2057
|
-
});
|
2058
|
-
};
|
2269
|
+
resolve: function(val) {
|
2270
|
+
var deferred = $.Deferred().resolve(val);
|
2271
|
+
var promise = deferred.promise();
|
2059
2272
|
|
2060
|
-
|
2061
|
-
q.push(runFunc);
|
2273
|
+
attachImmediatelyResolvingThen(promise, val);
|
2062
2274
|
|
2063
|
-
|
2064
|
-
|
2065
|
-
runFunc();
|
2066
|
-
}
|
2067
|
-
});
|
2068
|
-
}
|
2275
|
+
return promise;
|
2276
|
+
},
|
2069
2277
|
|
2070
|
-
|
2071
|
-
|
2072
|
-
|
2073
|
-
addTask; // if not a number (null/undefined/false), no debounce at all
|
2278
|
+
reject: function() {
|
2279
|
+
var deferred = $.Deferred().reject();
|
2280
|
+
var promise = deferred.promise();
|
2074
2281
|
|
2075
|
-
|
2076
|
-
}
|
2282
|
+
attachImmediatelyRejectingThen(promise);
|
2077
2283
|
|
2078
|
-
|
2284
|
+
return promise;
|
2285
|
+
}
|
2079
2286
|
|
2080
|
-
|
2081
|
-
q = new TaskQueue();
|
2287
|
+
};
|
2082
2288
|
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2289
|
+
|
2290
|
+
function attachImmediatelyResolvingThen(promise, val) {
|
2291
|
+
promise.then = function(onResolve) {
|
2292
|
+
if (typeof onResolve === 'function') {
|
2293
|
+
onResolve(val);
|
2294
|
+
}
|
2295
|
+
return promise; // for chaining
|
2296
|
+
};
|
2088
2297
|
}
|
2089
2298
|
|
2090
|
-
var cnt = 0;
|
2091
2299
|
|
2092
|
-
function
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
2300
|
+
function attachImmediatelyRejectingThen(promise) {
|
2301
|
+
promise.then = function(onResolve, onReject) {
|
2302
|
+
if (typeof onReject === 'function') {
|
2303
|
+
onReject();
|
2304
|
+
}
|
2305
|
+
return promise; // for chaining
|
2306
|
+
};
|
2097
2307
|
}
|
2098
2308
|
|
2099
|
-
|
2100
|
-
|
2309
|
+
|
2310
|
+
FC.Promise = Promise;
|
2101
2311
|
|
2102
2312
|
;;
|
2103
2313
|
|
2104
|
-
var
|
2314
|
+
var TaskQueue = Class.extend(EmitterMixin, {
|
2105
2315
|
|
2106
|
-
|
2107
|
-
|
2316
|
+
q: null,
|
2317
|
+
isPaused: false,
|
2318
|
+
isRunning: false,
|
2108
2319
|
|
2109
2320
|
|
2110
|
-
|
2111
|
-
|
2112
|
-
return this; // for chaining
|
2321
|
+
constructor: function() {
|
2322
|
+
this.q = [];
|
2113
2323
|
},
|
2114
2324
|
|
2115
2325
|
|
2116
|
-
|
2117
|
-
|
2118
|
-
|
2326
|
+
queue: function(/* taskFunc, taskFunc... */) {
|
2327
|
+
this.q.push.apply(this.q, arguments); // append
|
2328
|
+
this.tryStart();
|
2119
2329
|
},
|
2120
2330
|
|
2121
2331
|
|
2122
|
-
|
2123
|
-
|
2124
|
-
|
2125
|
-
// and forward them on to the original handler.
|
2126
|
-
var intercept = function(ev, extra) {
|
2127
|
-
return handler.apply(
|
2128
|
-
extra.context || this,
|
2129
|
-
extra.args || []
|
2130
|
-
);
|
2131
|
-
};
|
2332
|
+
pause: function() {
|
2333
|
+
this.isPaused = true;
|
2334
|
+
},
|
2132
2335
|
|
2133
|
-
// mimick jQuery's internal "proxy" system (risky, I know)
|
2134
|
-
// causing all functions with the same .guid to appear to be the same.
|
2135
|
-
// https://github.com/jquery/jquery/blob/2.2.4/src/core.js#L448
|
2136
|
-
// this is needed for calling .off with the original non-intercept handler.
|
2137
|
-
if (!handler.guid) {
|
2138
|
-
handler.guid = $.guid++;
|
2139
|
-
}
|
2140
|
-
intercept.guid = handler.guid;
|
2141
2336
|
|
2142
|
-
|
2337
|
+
resume: function() {
|
2338
|
+
this.isPaused = false;
|
2339
|
+
this.tryStart();
|
2143
2340
|
},
|
2144
2341
|
|
2145
2342
|
|
2146
|
-
|
2147
|
-
|
2343
|
+
tryStart: function() {
|
2344
|
+
if (!this.isRunning && this.canRunNext()) {
|
2345
|
+
this.isRunning = true;
|
2346
|
+
this.trigger('start');
|
2347
|
+
this.runNext();
|
2348
|
+
}
|
2349
|
+
},
|
2148
2350
|
|
2149
|
-
|
2351
|
+
|
2352
|
+
canRunNext: function() {
|
2353
|
+
return !this.isPaused && this.q.length;
|
2150
2354
|
},
|
2151
2355
|
|
2152
2356
|
|
2153
|
-
|
2154
|
-
|
2357
|
+
runNext: function() { // does not check canRunNext
|
2358
|
+
this.runTask(this.q.shift());
|
2359
|
+
},
|
2155
2360
|
|
2156
|
-
// pass in "extra" info to the intercept
|
2157
|
-
$(this).triggerHandler(types, { args: args });
|
2158
2361
|
|
2159
|
-
|
2362
|
+
runTask: function(task) {
|
2363
|
+
this.runTaskFunc(task);
|
2160
2364
|
},
|
2161
2365
|
|
2162
2366
|
|
2163
|
-
|
2367
|
+
runTaskFunc: function(taskFunc) {
|
2368
|
+
var _this = this;
|
2369
|
+
var res = taskFunc();
|
2164
2370
|
|
2165
|
-
|
2166
|
-
|
2167
|
-
|
2371
|
+
if (res && res.then) {
|
2372
|
+
res.then(done);
|
2373
|
+
}
|
2374
|
+
else {
|
2375
|
+
done();
|
2376
|
+
}
|
2168
2377
|
|
2169
|
-
|
2378
|
+
function done() {
|
2379
|
+
if (_this.canRunNext()) {
|
2380
|
+
_this.runNext();
|
2381
|
+
}
|
2382
|
+
else {
|
2383
|
+
_this.isRunning = false;
|
2384
|
+
_this.trigger('stop');
|
2385
|
+
}
|
2386
|
+
}
|
2170
2387
|
}
|
2171
2388
|
|
2172
|
-
};
|
2389
|
+
});
|
2390
|
+
|
2391
|
+
FC.TaskQueue = TaskQueue;
|
2173
2392
|
|
2174
2393
|
;;
|
2175
2394
|
|
2176
|
-
|
2177
|
-
Utility methods for easily listening to events on another object,
|
2178
|
-
and more importantly, easily unlistening from them.
|
2179
|
-
*/
|
2180
|
-
var ListenerMixin = FC.ListenerMixin = (function() {
|
2181
|
-
var guid = 0;
|
2182
|
-
var ListenerMixin = {
|
2395
|
+
var RenderQueue = TaskQueue.extend({
|
2183
2396
|
|
2184
|
-
|
2397
|
+
waitsByNamespace: null,
|
2398
|
+
waitNamespace: null,
|
2399
|
+
waitId: null,
|
2185
2400
|
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2401
|
+
|
2402
|
+
constructor: function(waitsByNamespace) {
|
2403
|
+
TaskQueue.call(this); // super-constructor
|
2404
|
+
|
2405
|
+
this.waitsByNamespace = waitsByNamespace || {};
|
2406
|
+
},
|
2407
|
+
|
2408
|
+
|
2409
|
+
queue: function(taskFunc, namespace, type) {
|
2410
|
+
var task = {
|
2411
|
+
func: taskFunc,
|
2412
|
+
namespace: namespace,
|
2413
|
+
type: type
|
2414
|
+
};
|
2415
|
+
var waitMs;
|
2416
|
+
|
2417
|
+
if (namespace) {
|
2418
|
+
waitMs = this.waitsByNamespace[namespace];
|
2419
|
+
}
|
2420
|
+
|
2421
|
+
if (this.waitNamespace) {
|
2422
|
+
if (namespace === this.waitNamespace && waitMs != null) {
|
2423
|
+
this.delayWait(waitMs);
|
2424
|
+
}
|
2425
|
+
else {
|
2426
|
+
this.clearWait();
|
2427
|
+
this.tryStart();
|
2428
|
+
}
|
2429
|
+
}
|
2430
|
+
|
2431
|
+
if (this.compoundTask(task)) { // appended to queue?
|
2432
|
+
|
2433
|
+
if (!this.waitNamespace && waitMs != null) {
|
2434
|
+
this.startWait(namespace, waitMs);
|
2435
|
+
}
|
2436
|
+
else {
|
2437
|
+
this.tryStart();
|
2438
|
+
}
|
2439
|
+
}
|
2440
|
+
},
|
2441
|
+
|
2442
|
+
|
2443
|
+
startWait: function(namespace, waitMs) {
|
2444
|
+
this.waitNamespace = namespace;
|
2445
|
+
this.spawnWait(waitMs);
|
2446
|
+
},
|
2447
|
+
|
2448
|
+
|
2449
|
+
delayWait: function(waitMs) {
|
2450
|
+
clearTimeout(this.waitId);
|
2451
|
+
this.spawnWait(waitMs);
|
2452
|
+
},
|
2453
|
+
|
2454
|
+
|
2455
|
+
spawnWait: function(waitMs) {
|
2456
|
+
var _this = this;
|
2457
|
+
|
2458
|
+
this.waitId = setTimeout(function() {
|
2459
|
+
_this.waitNamespace = null;
|
2460
|
+
_this.tryStart();
|
2461
|
+
}, waitMs);
|
2462
|
+
},
|
2463
|
+
|
2464
|
+
|
2465
|
+
clearWait: function() {
|
2466
|
+
if (this.waitNamespace) {
|
2467
|
+
clearTimeout(this.waitId);
|
2468
|
+
this.waitId = null;
|
2469
|
+
this.waitNamespace = null;
|
2470
|
+
}
|
2471
|
+
},
|
2472
|
+
|
2473
|
+
|
2474
|
+
canRunNext: function() {
|
2475
|
+
if (!TaskQueue.prototype.canRunNext.apply(this, arguments)) {
|
2476
|
+
return false;
|
2477
|
+
}
|
2478
|
+
|
2479
|
+
// waiting for a certain namespace to stop receiving tasks?
|
2480
|
+
if (this.waitNamespace) {
|
2481
|
+
|
2482
|
+
// if there was a different namespace task in the meantime,
|
2483
|
+
// that forces all previously-waiting tasks to suddenly execute.
|
2484
|
+
// TODO: find a way to do this in constant time.
|
2485
|
+
for (var q = this.q, i = 0; i < q.length; i++) {
|
2486
|
+
if (q[i].namespace !== this.waitNamespace) {
|
2487
|
+
return true; // allow execution
|
2488
|
+
}
|
2489
|
+
}
|
2490
|
+
|
2491
|
+
return false;
|
2492
|
+
}
|
2493
|
+
|
2494
|
+
return true;
|
2495
|
+
},
|
2496
|
+
|
2497
|
+
|
2498
|
+
runTask: function(task) {
|
2499
|
+
this.runTaskFunc(task.func);
|
2500
|
+
},
|
2501
|
+
|
2502
|
+
|
2503
|
+
compoundTask: function(newTask) {
|
2504
|
+
var q = this.q;
|
2505
|
+
var shouldAppend = true;
|
2506
|
+
var i, task;
|
2507
|
+
|
2508
|
+
if (newTask.namespace) {
|
2509
|
+
|
2510
|
+
if (newTask.type === 'destroy' || newTask.type === 'init') {
|
2511
|
+
|
2512
|
+
// remove all add/remove ops with same namespace, regardless of order
|
2513
|
+
for (i = q.length - 1; i >= 0; i--) {
|
2514
|
+
task = q[i];
|
2515
|
+
|
2516
|
+
if (
|
2517
|
+
task.namespace === newTask.namespace &&
|
2518
|
+
(task.type === 'add' || task.type === 'remove')
|
2519
|
+
) {
|
2520
|
+
q.splice(i, 1); // remove task
|
2521
|
+
}
|
2522
|
+
}
|
2523
|
+
|
2524
|
+
if (newTask.type === 'destroy') {
|
2525
|
+
// eat away final init/destroy operation
|
2526
|
+
if (q.length) {
|
2527
|
+
task = q[q.length - 1]; // last task
|
2528
|
+
|
2529
|
+
if (task.namespace === newTask.namespace) {
|
2530
|
+
|
2531
|
+
// the init and our destroy cancel each other out
|
2532
|
+
if (task.type === 'init') {
|
2533
|
+
shouldAppend = false;
|
2534
|
+
q.pop();
|
2535
|
+
}
|
2536
|
+
// prefer to use the destroy operation that's already present
|
2537
|
+
else if (task.type === 'destroy') {
|
2538
|
+
shouldAppend = false;
|
2539
|
+
}
|
2540
|
+
}
|
2541
|
+
}
|
2542
|
+
}
|
2543
|
+
else if (newTask.type === 'init') {
|
2544
|
+
// eat away final init operation
|
2545
|
+
if (q.length) {
|
2546
|
+
task = q[q.length - 1]; // last task
|
2547
|
+
|
2548
|
+
if (
|
2549
|
+
task.namespace === newTask.namespace &&
|
2550
|
+
task.type === 'init'
|
2551
|
+
) {
|
2552
|
+
// our init operation takes precedence
|
2553
|
+
q.pop();
|
2554
|
+
}
|
2555
|
+
}
|
2556
|
+
}
|
2557
|
+
}
|
2558
|
+
}
|
2559
|
+
|
2560
|
+
if (shouldAppend) {
|
2561
|
+
q.push(newTask);
|
2562
|
+
}
|
2563
|
+
|
2564
|
+
return shouldAppend;
|
2565
|
+
}
|
2566
|
+
|
2567
|
+
});
|
2568
|
+
|
2569
|
+
FC.RenderQueue = RenderQueue;
|
2570
|
+
|
2571
|
+
;;
|
2572
|
+
|
2573
|
+
var EmitterMixin = FC.EmitterMixin = {
|
2574
|
+
|
2575
|
+
// jQuery-ification via $(this) allows a non-DOM object to have
|
2576
|
+
// the same event handling capabilities (including namespaces).
|
2577
|
+
|
2578
|
+
|
2579
|
+
on: function(types, handler) {
|
2580
|
+
$(this).on(types, this._prepareIntercept(handler));
|
2581
|
+
return this; // for chaining
|
2582
|
+
},
|
2583
|
+
|
2584
|
+
|
2585
|
+
one: function(types, handler) {
|
2586
|
+
$(this).one(types, this._prepareIntercept(handler));
|
2587
|
+
return this; // for chaining
|
2588
|
+
},
|
2589
|
+
|
2590
|
+
|
2591
|
+
_prepareIntercept: function(handler) {
|
2592
|
+
// handlers are always called with an "event" object as their first param.
|
2593
|
+
// sneak the `this` context and arguments into the extra parameter object
|
2594
|
+
// and forward them on to the original handler.
|
2595
|
+
var intercept = function(ev, extra) {
|
2596
|
+
return handler.apply(
|
2597
|
+
extra.context || this,
|
2598
|
+
extra.args || []
|
2599
|
+
);
|
2600
|
+
};
|
2601
|
+
|
2602
|
+
// mimick jQuery's internal "proxy" system (risky, I know)
|
2603
|
+
// causing all functions with the same .guid to appear to be the same.
|
2604
|
+
// https://github.com/jquery/jquery/blob/2.2.4/src/core.js#L448
|
2605
|
+
// this is needed for calling .off with the original non-intercept handler.
|
2606
|
+
if (!handler.guid) {
|
2607
|
+
handler.guid = $.guid++;
|
2608
|
+
}
|
2609
|
+
intercept.guid = handler.guid;
|
2610
|
+
|
2611
|
+
return intercept;
|
2612
|
+
},
|
2613
|
+
|
2614
|
+
|
2615
|
+
off: function(types, handler) {
|
2616
|
+
$(this).off(types, handler);
|
2617
|
+
|
2618
|
+
return this; // for chaining
|
2619
|
+
},
|
2620
|
+
|
2621
|
+
|
2622
|
+
trigger: function(types) {
|
2623
|
+
var args = Array.prototype.slice.call(arguments, 1); // arguments after the first
|
2624
|
+
|
2625
|
+
// pass in "extra" info to the intercept
|
2626
|
+
$(this).triggerHandler(types, { args: args });
|
2627
|
+
|
2628
|
+
return this; // for chaining
|
2629
|
+
},
|
2630
|
+
|
2631
|
+
|
2632
|
+
triggerWith: function(types, context, args) {
|
2633
|
+
|
2634
|
+
// `triggerHandler` is less reliant on the DOM compared to `trigger`.
|
2635
|
+
// pass in "extra" info to the intercept.
|
2636
|
+
$(this).triggerHandler(types, { context: context, args: args });
|
2637
|
+
|
2638
|
+
return this; // for chaining
|
2639
|
+
}
|
2640
|
+
|
2641
|
+
};
|
2642
|
+
|
2643
|
+
;;
|
2644
|
+
|
2645
|
+
/*
|
2646
|
+
Utility methods for easily listening to events on another object,
|
2647
|
+
and more importantly, easily unlistening from them.
|
2648
|
+
*/
|
2649
|
+
var ListenerMixin = FC.ListenerMixin = (function() {
|
2650
|
+
var guid = 0;
|
2651
|
+
var ListenerMixin = {
|
2652
|
+
|
2653
|
+
listenerId: null,
|
2654
|
+
|
2655
|
+
/*
|
2656
|
+
Given an `other` object that has on/off methods, bind the given `callback` to an event by the given name.
|
2657
|
+
The `callback` will be called with the `this` context of the object that .listenTo is being called on.
|
2658
|
+
Can be called:
|
2659
|
+
.listenTo(other, eventName, callback)
|
2660
|
+
OR
|
2661
|
+
.listenTo(other, {
|
2662
|
+
eventName1: callback1,
|
2663
|
+
eventName2: callback2
|
2664
|
+
})
|
2196
2665
|
*/
|
2197
2666
|
listenTo: function(other, arg, callback) {
|
2198
2667
|
if (typeof arg === 'object') { // given dictionary of callbacks
|
@@ -4734,7 +5203,7 @@ Grid.mixin({
|
|
4734
5203
|
if (businessHours == null) {
|
4735
5204
|
// fallback
|
4736
5205
|
// access from calendawr. don't access from view. doesn't update with dynamic options.
|
4737
|
-
businessHours = calendar.
|
5206
|
+
businessHours = calendar.opt('businessHours');
|
4738
5207
|
}
|
4739
5208
|
|
4740
5209
|
events = calendar.computeBusinessHourEvents(wholeDay, businessHours);
|
@@ -5802,7 +6271,9 @@ Grid.mixin({
|
|
5802
6271
|
});
|
5803
6272
|
}
|
5804
6273
|
|
5805
|
-
|
6274
|
+
if (range.end > start) {
|
6275
|
+
start = range.end;
|
6276
|
+
}
|
5806
6277
|
}
|
5807
6278
|
|
5808
6279
|
// add the span of time after the last event (if there is any)
|
@@ -8686,7 +9157,7 @@ function isSlotSegCollision(seg1, seg2) {
|
|
8686
9157
|
/* An abstract class from which other views inherit from
|
8687
9158
|
----------------------------------------------------------------------------------------------------------------------*/
|
8688
9159
|
|
8689
|
-
var View = FC.View =
|
9160
|
+
var View = FC.View = Model.extend({
|
8690
9161
|
|
8691
9162
|
type: null, // subclass' view name (string)
|
8692
9163
|
name: null, // deprecated. use `type` instead
|
@@ -8697,14 +9168,13 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8697
9168
|
options: null, // hash containing all options. already merged with view-specific-options
|
8698
9169
|
el: null, // the view's containing element. set by Calendar
|
8699
9170
|
|
8700
|
-
|
8701
|
-
|
8702
|
-
|
8703
|
-
|
8704
|
-
isEventsBound: false,
|
8705
|
-
isEventsSet: false,
|
9171
|
+
renderQueue: null,
|
9172
|
+
batchRenderDepth: 0,
|
9173
|
+
isDatesRendered: false,
|
8706
9174
|
isEventsRendered: false,
|
8707
|
-
|
9175
|
+
isBaseRendered: false, // related to viewRender/viewDestroy triggers
|
9176
|
+
|
9177
|
+
queuedScroll: null,
|
8708
9178
|
|
8709
9179
|
isRTL: false,
|
8710
9180
|
isSelected: false, // boolean whether a range of time is user-selected or not
|
@@ -8730,6 +9200,7 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8730
9200
|
|
8731
9201
|
|
8732
9202
|
constructor: function(calendar, viewSpec) {
|
9203
|
+
Model.prototype.constructor.call(this);
|
8733
9204
|
|
8734
9205
|
this.calendar = calendar;
|
8735
9206
|
this.viewSpec = viewSpec;
|
@@ -8748,13 +9219,60 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8748
9219
|
|
8749
9220
|
this.eventOrderSpecs = parseFieldSpecs(this.opt('eventOrder'));
|
8750
9221
|
|
8751
|
-
this.
|
8752
|
-
this.
|
9222
|
+
this.renderQueue = this.buildRenderQueue();
|
9223
|
+
this.initAutoBatchRender();
|
8753
9224
|
|
8754
9225
|
this.initialize();
|
8755
9226
|
},
|
8756
9227
|
|
8757
9228
|
|
9229
|
+
buildRenderQueue: function() {
|
9230
|
+
var _this = this;
|
9231
|
+
var renderQueue = new RenderQueue({
|
9232
|
+
event: this.opt('eventRenderWait')
|
9233
|
+
});
|
9234
|
+
|
9235
|
+
renderQueue.on('start', function() {
|
9236
|
+
_this.freezeHeight();
|
9237
|
+
_this.addScroll(_this.queryScroll());
|
9238
|
+
});
|
9239
|
+
|
9240
|
+
renderQueue.on('stop', function() {
|
9241
|
+
_this.thawHeight();
|
9242
|
+
_this.popScroll();
|
9243
|
+
});
|
9244
|
+
|
9245
|
+
return renderQueue;
|
9246
|
+
},
|
9247
|
+
|
9248
|
+
|
9249
|
+
initAutoBatchRender: function() {
|
9250
|
+
var _this = this;
|
9251
|
+
|
9252
|
+
this.on('before:change', function() {
|
9253
|
+
_this.startBatchRender();
|
9254
|
+
});
|
9255
|
+
|
9256
|
+
this.on('change', function() {
|
9257
|
+
_this.stopBatchRender();
|
9258
|
+
});
|
9259
|
+
},
|
9260
|
+
|
9261
|
+
|
9262
|
+
startBatchRender: function() {
|
9263
|
+
if (!(this.batchRenderDepth++)) {
|
9264
|
+
this.renderQueue.pause();
|
9265
|
+
}
|
9266
|
+
},
|
9267
|
+
|
9268
|
+
|
9269
|
+
stopBatchRender: function() {
|
9270
|
+
if (!(--this.batchRenderDepth)) {
|
9271
|
+
this.renderQueue.resume();
|
9272
|
+
}
|
9273
|
+
},
|
9274
|
+
|
9275
|
+
|
8758
9276
|
// A good place for subclasses to initialize member variables
|
8759
9277
|
initialize: function() {
|
8760
9278
|
// subclasses can implement
|
@@ -8781,29 +9299,6 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8781
9299
|
},
|
8782
9300
|
|
8783
9301
|
|
8784
|
-
// Returns a proxy of the given promise that will be rejected if the given event fires
|
8785
|
-
// before the promise resolves.
|
8786
|
-
rejectOn: function(eventName, promise) {
|
8787
|
-
var _this = this;
|
8788
|
-
|
8789
|
-
return new Promise(function(resolve, reject) {
|
8790
|
-
_this.one(eventName, reject);
|
8791
|
-
|
8792
|
-
function cleanup() {
|
8793
|
-
_this.off(eventName, reject);
|
8794
|
-
}
|
8795
|
-
|
8796
|
-
promise.then(function(res) { // success
|
8797
|
-
cleanup();
|
8798
|
-
resolve(res);
|
8799
|
-
}, function() { // failure
|
8800
|
-
cleanup();
|
8801
|
-
reject();
|
8802
|
-
});
|
8803
|
-
});
|
8804
|
-
},
|
8805
|
-
|
8806
|
-
|
8807
9302
|
/* Title and Date Formatting
|
8808
9303
|
------------------------------------------------------------------------------------------------------------------*/
|
8809
9304
|
|
@@ -8936,6 +9431,7 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8936
9431
|
setElement: function(el) {
|
8937
9432
|
this.el = el;
|
8938
9433
|
this.bindGlobalHandlers();
|
9434
|
+
this.bindBaseRenderHandlers();
|
8939
9435
|
this.renderSkeleton();
|
8940
9436
|
},
|
8941
9437
|
|
@@ -8947,6 +9443,7 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8947
9443
|
this.unrenderSkeleton();
|
8948
9444
|
|
8949
9445
|
this.unbindGlobalHandlers();
|
9446
|
+
this.unbindBaseRenderHandlers();
|
8950
9447
|
|
8951
9448
|
this.el.remove();
|
8952
9449
|
// NOTE: don't null-out this.el in case the View was destroyed within an API callback.
|
@@ -8972,165 +9469,155 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
8972
9469
|
|
8973
9470
|
|
8974
9471
|
setDate: function(date) {
|
8975
|
-
var
|
9472
|
+
var currentDateProfile = this.get('dateProfile');
|
9473
|
+
var newDateProfile = this.buildDateProfile(date, null, true); // forceToValid=true
|
9474
|
+
|
9475
|
+
if (
|
9476
|
+
!currentDateProfile ||
|
9477
|
+
!isRangesEqual(currentDateProfile.activeRange, newDateProfile.activeRange)
|
9478
|
+
) {
|
9479
|
+
this.set('dateProfile', newDateProfile);
|
9480
|
+
}
|
8976
9481
|
|
8977
|
-
|
8978
|
-
this.handleRawDate(date);
|
8979
|
-
this.trigger(isReset ? 'dateReset' : 'dateSet', date);
|
9482
|
+
return newDateProfile.date;
|
8980
9483
|
},
|
8981
9484
|
|
8982
9485
|
|
8983
9486
|
unsetDate: function() {
|
8984
|
-
|
8985
|
-
this.isDateSet = false;
|
8986
|
-
this.handleDateUnset();
|
8987
|
-
this.trigger('dateUnset');
|
8988
|
-
}
|
9487
|
+
this.unset('dateProfile');
|
8989
9488
|
},
|
8990
9489
|
|
8991
9490
|
|
8992
|
-
// Date
|
9491
|
+
// Date Rendering
|
8993
9492
|
// -----------------------------------------------------------------------------------------------------------------
|
8994
9493
|
|
8995
9494
|
|
8996
|
-
|
9495
|
+
requestDateRender: function(dateProfile) {
|
8997
9496
|
var _this = this;
|
8998
|
-
var dateProfile = this.buildDateProfile(date, null, true); // forceToValid=true
|
8999
9497
|
|
9000
|
-
|
9001
|
-
|
9002
|
-
}
|
9003
|
-
else {
|
9004
|
-
// View might have no date change, but still needs to render (because of a view unrender/rerender).
|
9005
|
-
// Wait for possible queued unrenders. TODO: refactor.
|
9006
|
-
this.dateRenderQueue.add(function() {
|
9007
|
-
if (!_this.isDateRendered) {
|
9008
|
-
_this.handleDate(dateProfile);
|
9009
|
-
}
|
9010
|
-
});
|
9011
|
-
}
|
9498
|
+
this.renderQueue.queue(function() {
|
9499
|
+
_this.executeDateRender(dateProfile);
|
9500
|
+
}, 'date', 'init');
|
9012
9501
|
},
|
9013
9502
|
|
9014
9503
|
|
9015
|
-
|
9504
|
+
requestDateUnrender: function() {
|
9016
9505
|
var _this = this;
|
9017
9506
|
|
9018
|
-
this.
|
9019
|
-
|
9020
|
-
|
9021
|
-
_this.bindEvents(); // will request events
|
9022
|
-
});
|
9507
|
+
this.renderQueue.queue(function() {
|
9508
|
+
_this.executeDateUnrender();
|
9509
|
+
}, 'date', 'destroy');
|
9023
9510
|
},
|
9024
9511
|
|
9025
9512
|
|
9026
|
-
|
9027
|
-
|
9028
|
-
|
9513
|
+
// Event Data
|
9514
|
+
// -----------------------------------------------------------------------------------------------------------------
|
9515
|
+
|
9516
|
+
|
9517
|
+
fetchInitialEvents: function(dateProfile) {
|
9518
|
+
return this.calendar.requestEvents(
|
9519
|
+
dateProfile.activeRange.start,
|
9520
|
+
dateProfile.activeRange.end
|
9521
|
+
);
|
9029
9522
|
},
|
9030
9523
|
|
9031
9524
|
|
9032
|
-
|
9033
|
-
|
9525
|
+
bindEventChanges: function() {
|
9526
|
+
this.listenTo(this.calendar, 'eventsReset', this.resetEvents);
|
9527
|
+
},
|
9034
9528
|
|
9035
9529
|
|
9036
|
-
|
9037
|
-
|
9038
|
-
|
9530
|
+
unbindEventChanges: function() {
|
9531
|
+
this.stopListeningTo(this.calendar, 'eventsReset');
|
9532
|
+
},
|
9039
9533
|
|
9040
|
-
|
9041
|
-
|
9042
|
-
|
9534
|
+
|
9535
|
+
setEvents: function(events) {
|
9536
|
+
this.set('currentEvents', events);
|
9537
|
+
this.set('hasEvents', true);
|
9043
9538
|
},
|
9044
9539
|
|
9045
9540
|
|
9046
|
-
|
9047
|
-
|
9541
|
+
unsetEvents: function() {
|
9542
|
+
this.unset('currentEvents');
|
9543
|
+
this.unset('hasEvents');
|
9544
|
+
},
|
9048
9545
|
|
9049
|
-
|
9050
|
-
|
9051
|
-
|
9546
|
+
|
9547
|
+
resetEvents: function(events) {
|
9548
|
+
this.startBatchRender();
|
9549
|
+
this.unsetEvents();
|
9550
|
+
this.setEvents(events);
|
9551
|
+
this.stopBatchRender();
|
9052
9552
|
},
|
9053
9553
|
|
9054
9554
|
|
9055
|
-
//
|
9555
|
+
// Event Rendering
|
9056
9556
|
// -----------------------------------------------------------------------------------------------------------------
|
9057
9557
|
|
9058
9558
|
|
9059
|
-
|
9060
|
-
executeDateRender: function(dateProfile) {
|
9559
|
+
requestEventsRender: function(events) {
|
9061
9560
|
var _this = this;
|
9062
9561
|
|
9063
|
-
|
9064
|
-
_this.
|
9065
|
-
}
|
9562
|
+
this.renderQueue.queue(function() {
|
9563
|
+
_this.executeEventsRender(events);
|
9564
|
+
}, 'event', 'init');
|
9565
|
+
},
|
9066
9566
|
|
9067
|
-
this.updateTitle();
|
9068
|
-
this.calendar.updateToolbarButtons();
|
9069
9567
|
|
9070
|
-
|
9071
|
-
|
9072
|
-
this.captureInitialScroll();
|
9073
|
-
}
|
9074
|
-
else {
|
9075
|
-
this.captureScroll(); // a rerender of the current date
|
9076
|
-
}
|
9568
|
+
requestEventsUnrender: function() {
|
9569
|
+
var _this = this;
|
9077
9570
|
|
9078
|
-
this.
|
9571
|
+
this.renderQueue.queue(function() {
|
9572
|
+
_this.executeEventsUnrender();
|
9573
|
+
}, 'event', 'destroy');
|
9574
|
+
},
|
9079
9575
|
|
9080
|
-
// potential issue: date-unrendering will happen with the *new* range
|
9081
|
-
return this.executeDateUnrender().then(function() {
|
9082
9576
|
|
9083
|
-
|
9084
|
-
|
9085
|
-
}
|
9577
|
+
// Date High-level Rendering
|
9578
|
+
// -----------------------------------------------------------------------------------------------------------------
|
9086
9579
|
|
9087
|
-
_this.renderDates();
|
9088
|
-
_this.updateSize();
|
9089
|
-
_this.renderBusinessHours(); // might need coordinates, so should go after updateSize()
|
9090
|
-
_this.startNowIndicator();
|
9091
9580
|
|
9092
|
-
|
9093
|
-
|
9581
|
+
// if dateProfile not specified, uses current
|
9582
|
+
executeDateRender: function(dateProfile, skipScroll) {
|
9094
9583
|
|
9095
|
-
|
9096
|
-
|
9097
|
-
|
9098
|
-
});
|
9099
|
-
},
|
9584
|
+
this.setDateProfileForRendering(dateProfile);
|
9585
|
+
this.updateTitle();
|
9586
|
+
this.calendar.updateToolbarButtons();
|
9100
9587
|
|
9588
|
+
if (this.render) {
|
9589
|
+
this.render(); // TODO: deprecate
|
9590
|
+
}
|
9101
9591
|
|
9102
|
-
|
9103
|
-
|
9592
|
+
this.renderDates();
|
9593
|
+
this.updateSize();
|
9594
|
+
this.renderBusinessHours(); // might need coordinates, so should go after updateSize()
|
9595
|
+
this.startNowIndicator();
|
9104
9596
|
|
9105
|
-
if (
|
9106
|
-
|
9597
|
+
if (!skipScroll) {
|
9598
|
+
this.addScroll(this.computeInitialDateScroll());
|
9599
|
+
}
|
9107
9600
|
|
9108
|
-
|
9109
|
-
|
9110
|
-
|
9111
|
-
_this.unrenderBusinessHours();
|
9112
|
-
_this.unrenderDates();
|
9601
|
+
this.isDatesRendered = true;
|
9602
|
+
this.trigger('datesRendered');
|
9603
|
+
},
|
9113
9604
|
|
9114
|
-
if (_this.destroy) {
|
9115
|
-
_this.destroy(); // TODO: deprecate
|
9116
|
-
}
|
9117
9605
|
|
9118
|
-
|
9119
|
-
_this.trigger('dateUnrender');
|
9120
|
-
});
|
9121
|
-
}
|
9122
|
-
else {
|
9123
|
-
return Promise.resolve();
|
9124
|
-
}
|
9125
|
-
},
|
9606
|
+
executeDateUnrender: function() {
|
9126
9607
|
|
9608
|
+
this.unselect();
|
9609
|
+
this.stopNowIndicator();
|
9127
9610
|
|
9128
|
-
|
9129
|
-
// -----------------------------------------------------------------------------------------------------------------
|
9611
|
+
this.trigger('before:datesUnrendered');
|
9130
9612
|
|
9613
|
+
this.unrenderBusinessHours();
|
9614
|
+
this.unrenderDates();
|
9615
|
+
|
9616
|
+
if (this.destroy) {
|
9617
|
+
this.destroy(); // TODO: deprecate
|
9618
|
+
}
|
9131
9619
|
|
9132
|
-
|
9133
|
-
this.triggerRender();
|
9620
|
+
this.isDatesRendered = false;
|
9134
9621
|
},
|
9135
9622
|
|
9136
9623
|
|
@@ -9150,22 +9637,44 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9150
9637
|
},
|
9151
9638
|
|
9152
9639
|
|
9153
|
-
//
|
9154
|
-
//
|
9640
|
+
// Determing when the "meat" of the view is rendered (aka the base)
|
9641
|
+
// -----------------------------------------------------------------------------------------------------------------
|
9642
|
+
|
9643
|
+
|
9644
|
+
bindBaseRenderHandlers: function() {
|
9645
|
+
var _this = this;
|
9646
|
+
|
9647
|
+
this.on('datesRendered.baseHandler', function() {
|
9648
|
+
_this.onBaseRender();
|
9649
|
+
});
|
9650
|
+
|
9651
|
+
this.on('before:datesUnrendered.baseHandler', function() {
|
9652
|
+
_this.onBeforeBaseUnrender();
|
9653
|
+
});
|
9654
|
+
},
|
9655
|
+
|
9656
|
+
|
9657
|
+
unbindBaseRenderHandlers: function() {
|
9658
|
+
this.off('.baseHandler');
|
9659
|
+
},
|
9155
9660
|
|
9156
9661
|
|
9157
|
-
|
9158
|
-
|
9662
|
+
onBaseRender: function() {
|
9663
|
+
this.applyScreenState();
|
9159
9664
|
this.publiclyTrigger('viewRender', this, this, this.el);
|
9160
9665
|
},
|
9161
9666
|
|
9162
9667
|
|
9163
|
-
|
9164
|
-
|
9668
|
+
onBeforeBaseUnrender: function() {
|
9669
|
+
this.applyScreenState();
|
9165
9670
|
this.publiclyTrigger('viewDestroy', this, this, this.el);
|
9166
9671
|
},
|
9167
9672
|
|
9168
9673
|
|
9674
|
+
// Misc view rendering utils
|
9675
|
+
// -----------------------------------------------------------------------------------------------------------------
|
9676
|
+
|
9677
|
+
|
9169
9678
|
// Binds DOM handlers to elements that reside outside the view container, such as the document
|
9170
9679
|
bindGlobalHandlers: function() {
|
9171
9680
|
this.listenTo(GlobalEmitter.get(), {
|
@@ -9301,9 +9810,10 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9301
9810
|
|
9302
9811
|
// Refreshes anything dependant upon sizing of the container element of the grid
|
9303
9812
|
updateSize: function(isResize) {
|
9813
|
+
var scroll;
|
9304
9814
|
|
9305
9815
|
if (isResize) {
|
9306
|
-
this.
|
9816
|
+
scroll = this.queryScroll();
|
9307
9817
|
}
|
9308
9818
|
|
9309
9819
|
this.updateHeight(isResize);
|
@@ -9311,7 +9821,7 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9311
9821
|
this.updateNowIndicator();
|
9312
9822
|
|
9313
9823
|
if (isResize) {
|
9314
|
-
this.
|
9824
|
+
this.applyScroll(scroll);
|
9315
9825
|
}
|
9316
9826
|
},
|
9317
9827
|
|
@@ -9344,90 +9854,65 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9344
9854
|
------------------------------------------------------------------------------------------------------------------*/
|
9345
9855
|
|
9346
9856
|
|
9347
|
-
|
9348
|
-
|
9349
|
-
|
9350
|
-
|
9351
|
-
captureScroll: function() {
|
9352
|
-
if (!(this.capturedScrollDepth++)) {
|
9353
|
-
this.capturedScroll = this.isDateRendered ? this.queryScroll() : {}; // require a render first
|
9354
|
-
return true; // root?
|
9355
|
-
}
|
9356
|
-
return false;
|
9857
|
+
addForcedScroll: function(scroll) {
|
9858
|
+
this.addScroll(
|
9859
|
+
$.extend(scroll, { isForced: true })
|
9860
|
+
);
|
9357
9861
|
},
|
9358
9862
|
|
9359
9863
|
|
9360
|
-
|
9361
|
-
|
9362
|
-
this.capturedScroll.isInitial = true;
|
9864
|
+
addScroll: function(scroll) {
|
9865
|
+
var queuedScroll = this.queuedScroll || (this.queuedScroll = {});
|
9363
9866
|
|
9364
|
-
|
9365
|
-
|
9366
|
-
}
|
9367
|
-
else {
|
9368
|
-
this.capturedScroll.isComputed = true;
|
9369
|
-
}
|
9867
|
+
if (!queuedScroll.isForced) {
|
9868
|
+
$.extend(queuedScroll, scroll);
|
9370
9869
|
}
|
9371
9870
|
},
|
9372
9871
|
|
9373
9872
|
|
9374
|
-
|
9375
|
-
|
9376
|
-
|
9377
|
-
|
9378
|
-
if (scroll.isComputed) {
|
9379
|
-
if (isRoot) {
|
9380
|
-
// only compute initial scroll if it will actually be used (is the root capture)
|
9381
|
-
$.extend(scroll, this.computeInitialScroll());
|
9382
|
-
}
|
9383
|
-
else {
|
9384
|
-
scroll = null; // scroll couldn't be computed. don't apply it to the DOM
|
9385
|
-
}
|
9386
|
-
}
|
9873
|
+
popScroll: function() {
|
9874
|
+
this.applyQueuedScroll();
|
9875
|
+
this.queuedScroll = null;
|
9876
|
+
},
|
9387
9877
|
|
9388
|
-
if (scroll) {
|
9389
|
-
// we act immediately on a releaseScroll operation, as opposed to captureScroll.
|
9390
|
-
// if capture/release wraps a render operation that screws up the scroll,
|
9391
|
-
// we still want to restore it a good state after, regardless of depth.
|
9392
9878
|
|
9393
|
-
|
9394
|
-
|
9395
|
-
|
9396
|
-
else {
|
9397
|
-
this.setScroll(scroll);
|
9398
|
-
}
|
9879
|
+
applyQueuedScroll: function() {
|
9880
|
+
if (this.queuedScroll) {
|
9881
|
+
this.applyScroll(this.queuedScroll);
|
9399
9882
|
}
|
9400
9883
|
},
|
9401
9884
|
|
9402
9885
|
|
9403
|
-
|
9404
|
-
|
9405
|
-
|
9406
|
-
|
9886
|
+
queryScroll: function() {
|
9887
|
+
var scroll = {};
|
9888
|
+
|
9889
|
+
if (this.isDatesRendered) {
|
9890
|
+
$.extend(scroll, this.queryDateScroll());
|
9407
9891
|
}
|
9408
|
-
|
9892
|
+
|
9893
|
+
return scroll;
|
9409
9894
|
},
|
9410
9895
|
|
9411
9896
|
|
9412
|
-
|
9413
|
-
|
9897
|
+
applyScroll: function(scroll) {
|
9898
|
+
if (this.isDatesRendered) {
|
9899
|
+
this.applyDateScroll(scroll);
|
9900
|
+
}
|
9414
9901
|
},
|
9415
9902
|
|
9416
9903
|
|
9417
|
-
|
9418
|
-
return {};
|
9904
|
+
computeInitialDateScroll: function() {
|
9905
|
+
return {}; // subclasses must implement
|
9419
9906
|
},
|
9420
9907
|
|
9421
9908
|
|
9422
|
-
|
9423
|
-
|
9424
|
-
var exec = function() { _this.setScroll(scroll); };
|
9425
|
-
exec();
|
9426
|
-
setTimeout(exec, 0); // to surely clear the browser's initial scroll for the DOM
|
9909
|
+
queryDateScroll: function() {
|
9910
|
+
return {}; // subclasses must implement
|
9427
9911
|
},
|
9428
9912
|
|
9429
9913
|
|
9430
|
-
|
9914
|
+
applyDateScroll: function(scroll) {
|
9915
|
+
; // subclasses must implement
|
9431
9916
|
},
|
9432
9917
|
|
9433
9918
|
|
@@ -9445,165 +9930,27 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9445
9930
|
},
|
9446
9931
|
|
9447
9932
|
|
9448
|
-
// Event Binding/Unbinding
|
9449
|
-
// -----------------------------------------------------------------------------------------------------------------
|
9450
|
-
|
9451
|
-
|
9452
|
-
bindEvents: function() {
|
9453
|
-
var _this = this;
|
9454
|
-
|
9455
|
-
if (!this.isEventsBound) {
|
9456
|
-
this.isEventsBound = true;
|
9457
|
-
this.rejectOn('eventsUnbind', this.requestEvents()).then(function(events) { // TODO: test rejection
|
9458
|
-
_this.listenTo(_this.calendar, 'eventsReset', _this.setEvents);
|
9459
|
-
_this.setEvents(events);
|
9460
|
-
});
|
9461
|
-
}
|
9462
|
-
},
|
9463
|
-
|
9464
|
-
|
9465
|
-
unbindEvents: function() {
|
9466
|
-
if (this.isEventsBound) {
|
9467
|
-
this.isEventsBound = false;
|
9468
|
-
this.stopListeningTo(this.calendar, 'eventsReset');
|
9469
|
-
this.unsetEvents();
|
9470
|
-
this.trigger('eventsUnbind');
|
9471
|
-
}
|
9472
|
-
},
|
9473
|
-
|
9474
|
-
|
9475
|
-
// Event Setting/Unsetting
|
9476
|
-
// -----------------------------------------------------------------------------------------------------------------
|
9477
|
-
|
9478
|
-
|
9479
|
-
setEvents: function(events) {
|
9480
|
-
var isReset = this.isEventSet;
|
9481
|
-
|
9482
|
-
this.isEventsSet = true;
|
9483
|
-
this.handleEvents(events, isReset);
|
9484
|
-
this.trigger(isReset ? 'eventsReset' : 'eventsSet', events);
|
9485
|
-
},
|
9486
|
-
|
9487
|
-
|
9488
|
-
unsetEvents: function() {
|
9489
|
-
if (this.isEventsSet) {
|
9490
|
-
this.isEventsSet = false;
|
9491
|
-
this.handleEventsUnset();
|
9492
|
-
this.trigger('eventsUnset');
|
9493
|
-
}
|
9494
|
-
},
|
9495
|
-
|
9496
|
-
|
9497
|
-
whenEventsSet: function() {
|
9498
|
-
var _this = this;
|
9499
|
-
|
9500
|
-
if (this.isEventsSet) {
|
9501
|
-
return Promise.resolve(this.getCurrentEvents());
|
9502
|
-
}
|
9503
|
-
else {
|
9504
|
-
return new Promise(function(resolve) {
|
9505
|
-
_this.one('eventsSet', resolve);
|
9506
|
-
});
|
9507
|
-
}
|
9508
|
-
},
|
9509
|
-
|
9510
|
-
|
9511
|
-
// Event Handling
|
9512
|
-
// -----------------------------------------------------------------------------------------------------------------
|
9513
|
-
|
9514
|
-
|
9515
|
-
handleEvents: function(events, isReset) {
|
9516
|
-
this.requestEventsRender(events);
|
9517
|
-
},
|
9518
|
-
|
9519
|
-
|
9520
|
-
handleEventsUnset: function() {
|
9521
|
-
this.requestEventsUnrender();
|
9522
|
-
},
|
9523
|
-
|
9524
|
-
|
9525
|
-
// Event Render Queuing
|
9526
|
-
// -----------------------------------------------------------------------------------------------------------------
|
9527
|
-
|
9528
|
-
|
9529
|
-
// assumes any previous event renders have been cleared already
|
9530
|
-
requestEventsRender: function(events) {
|
9531
|
-
var _this = this;
|
9532
|
-
|
9533
|
-
return this.eventRenderQueue.add(function() { // might not return a promise if debounced!? bad
|
9534
|
-
return _this.executeEventsRender(events);
|
9535
|
-
});
|
9536
|
-
},
|
9537
|
-
|
9538
|
-
|
9539
|
-
requestEventsUnrender: function() {
|
9540
|
-
var _this = this;
|
9541
|
-
|
9542
|
-
if (this.isEventsRendered) {
|
9543
|
-
return this.eventRenderQueue.addQuickly(function() {
|
9544
|
-
return _this.executeEventsUnrender();
|
9545
|
-
});
|
9546
|
-
}
|
9547
|
-
else {
|
9548
|
-
return Promise.resolve();
|
9549
|
-
}
|
9550
|
-
},
|
9551
|
-
|
9552
|
-
|
9553
|
-
requestCurrentEventsRender: function() {
|
9554
|
-
if (this.isEventsSet) {
|
9555
|
-
this.requestEventsRender(this.getCurrentEvents());
|
9556
|
-
}
|
9557
|
-
else {
|
9558
|
-
return Promise.reject();
|
9559
|
-
}
|
9560
|
-
},
|
9561
|
-
|
9562
|
-
|
9563
9933
|
// Event High-level Rendering
|
9564
9934
|
// -----------------------------------------------------------------------------------------------------------------
|
9565
9935
|
|
9566
9936
|
|
9567
9937
|
executeEventsRender: function(events) {
|
9568
|
-
|
9569
|
-
|
9570
|
-
this.captureScroll();
|
9571
|
-
this.freezeHeight();
|
9938
|
+
this.renderEvents(events);
|
9939
|
+
this.isEventsRendered = true;
|
9572
9940
|
|
9573
|
-
|
9574
|
-
_this.renderEvents(events);
|
9575
|
-
|
9576
|
-
_this.thawHeight();
|
9577
|
-
_this.releaseScroll();
|
9578
|
-
|
9579
|
-
_this.isEventsRendered = true;
|
9580
|
-
_this.onEventsRender();
|
9581
|
-
_this.trigger('eventsRender');
|
9582
|
-
});
|
9941
|
+
this.onEventsRender();
|
9583
9942
|
},
|
9584
9943
|
|
9585
9944
|
|
9586
9945
|
executeEventsUnrender: function() {
|
9587
|
-
|
9588
|
-
this.onBeforeEventsUnrender();
|
9946
|
+
this.onBeforeEventsUnrender();
|
9589
9947
|
|
9590
|
-
|
9591
|
-
this.
|
9592
|
-
|
9593
|
-
if (this.destroyEvents) {
|
9594
|
-
this.destroyEvents(); // TODO: deprecate
|
9595
|
-
}
|
9596
|
-
|
9597
|
-
this.unrenderEvents();
|
9598
|
-
|
9599
|
-
this.thawHeight();
|
9600
|
-
this.releaseScroll();
|
9601
|
-
|
9602
|
-
this.isEventsRendered = false;
|
9603
|
-
this.trigger('eventsUnrender');
|
9948
|
+
if (this.destroyEvents) {
|
9949
|
+
this.destroyEvents(); // TODO: deprecate
|
9604
9950
|
}
|
9605
9951
|
|
9606
|
-
|
9952
|
+
this.unrenderEvents();
|
9953
|
+
this.isEventsRendered = false;
|
9607
9954
|
},
|
9608
9955
|
|
9609
9956
|
|
@@ -9613,6 +9960,8 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9613
9960
|
|
9614
9961
|
// Signals that all events have been rendered
|
9615
9962
|
onEventsRender: function() {
|
9963
|
+
this.applyScreenState();
|
9964
|
+
|
9616
9965
|
this.renderedEventSegEach(function(seg) {
|
9617
9966
|
this.publiclyTrigger('eventAfterRender', seg.event, seg.event, seg.el);
|
9618
9967
|
});
|
@@ -9622,12 +9971,21 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9622
9971
|
|
9623
9972
|
// Signals that all event elements are about to be removed
|
9624
9973
|
onBeforeEventsUnrender: function() {
|
9974
|
+
this.applyScreenState();
|
9975
|
+
|
9625
9976
|
this.renderedEventSegEach(function(seg) {
|
9626
9977
|
this.publiclyTrigger('eventDestroy', seg.event, seg.event, seg.el);
|
9627
9978
|
});
|
9628
9979
|
},
|
9629
9980
|
|
9630
9981
|
|
9982
|
+
applyScreenState: function() {
|
9983
|
+
this.thawHeight();
|
9984
|
+
this.freezeHeight();
|
9985
|
+
this.applyQueuedScroll();
|
9986
|
+
},
|
9987
|
+
|
9988
|
+
|
9631
9989
|
// Event Low-level Rendering
|
9632
9990
|
// -----------------------------------------------------------------------------------------------------------------
|
9633
9991
|
|
@@ -9644,23 +10002,6 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
9644
10002
|
},
|
9645
10003
|
|
9646
10004
|
|
9647
|
-
// Event Data Access
|
9648
|
-
// -----------------------------------------------------------------------------------------------------------------
|
9649
|
-
|
9650
|
-
|
9651
|
-
requestEvents: function() {
|
9652
|
-
return this.calendar.requestEvents(
|
9653
|
-
this.activeRange.start,
|
9654
|
-
this.activeRange.end
|
9655
|
-
);
|
9656
|
-
},
|
9657
|
-
|
9658
|
-
|
9659
|
-
getCurrentEvents: function() {
|
9660
|
-
return this.calendar.getPrunedEventCache();
|
9661
|
-
},
|
9662
|
-
|
9663
|
-
|
9664
10005
|
// Event Rendering Utils
|
9665
10006
|
// -----------------------------------------------------------------------------------------------------------------
|
9666
10007
|
|
@@ -10065,6 +10406,34 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
|
|
10065
10406
|
|
10066
10407
|
});
|
10067
10408
|
|
10409
|
+
|
10410
|
+
View.watch('displayingDates', [ 'dateProfile' ], function(deps) {
|
10411
|
+
this.requestDateRender(deps.dateProfile);
|
10412
|
+
}, function() {
|
10413
|
+
this.requestDateUnrender();
|
10414
|
+
});
|
10415
|
+
|
10416
|
+
|
10417
|
+
View.watch('initialEvents', [ 'dateProfile' ], function(deps) {
|
10418
|
+
return this.fetchInitialEvents(deps.dateProfile);
|
10419
|
+
});
|
10420
|
+
|
10421
|
+
|
10422
|
+
View.watch('bindingEvents', [ 'initialEvents' ], function(deps) {
|
10423
|
+
this.setEvents(deps.initialEvents);
|
10424
|
+
this.bindEventChanges();
|
10425
|
+
}, function() {
|
10426
|
+
this.unbindEventChanges();
|
10427
|
+
this.unsetEvents();
|
10428
|
+
});
|
10429
|
+
|
10430
|
+
|
10431
|
+
View.watch('displayingEvents', [ 'displayingDates', 'hasEvents' ], function() {
|
10432
|
+
this.requestEventsRender(this.get('currentEvents')); // if there were event mutations after initialEvents
|
10433
|
+
}, function() {
|
10434
|
+
this.requestEventsUnrender();
|
10435
|
+
});
|
10436
|
+
|
10068
10437
|
;;
|
10069
10438
|
|
10070
10439
|
View.mixin({
|
@@ -10088,10 +10457,6 @@ View.mixin({
|
|
10088
10457
|
// how far the current date will move for a prev/next operation
|
10089
10458
|
dateIncrement: null,
|
10090
10459
|
|
10091
|
-
// stores the *calendar's* current date after setDate
|
10092
|
-
// TODO: entirely Calendar's responsibility
|
10093
|
-
currentDate: null,
|
10094
|
-
|
10095
10460
|
minTime: null, // Duration object that denotes the first visible time of any given day
|
10096
10461
|
maxTime: null, // Duration object that denotes the exclusive visible end time of any given day
|
10097
10462
|
usesMinMaxTime: false, // whether minTime/maxTime will affect the activeRange. Views must opt-in.
|
@@ -10107,19 +10472,13 @@ View.mixin({
|
|
10107
10472
|
------------------------------------------------------------------------------------------------------------------*/
|
10108
10473
|
|
10109
10474
|
|
10110
|
-
|
10111
|
-
return this.activeRange && isRangesEqual(this.activeRange, dateProfile.activeRange);
|
10112
|
-
},
|
10113
|
-
|
10114
|
-
|
10115
|
-
setDateProfile: function(dateProfile) {
|
10475
|
+
setDateProfileForRendering: function(dateProfile) {
|
10116
10476
|
this.currentRange = dateProfile.currentRange;
|
10117
10477
|
this.currentRangeUnit = dateProfile.currentRangeUnit;
|
10118
10478
|
this.renderRange = dateProfile.renderRange;
|
10119
10479
|
this.activeRange = dateProfile.activeRange;
|
10120
10480
|
this.validRange = dateProfile.validRange;
|
10121
10481
|
this.dateIncrement = dateProfile.dateIncrement;
|
10122
|
-
this.currentDate = dateProfile.date;
|
10123
10482
|
this.minTime = dateProfile.minTime;
|
10124
10483
|
this.maxTime = dateProfile.maxTime;
|
10125
10484
|
|
@@ -10675,7 +11034,7 @@ function Toolbar(calendar, toolbarOptions) {
|
|
10675
11034
|
function render() {
|
10676
11035
|
var sections = toolbarOptions.layout;
|
10677
11036
|
|
10678
|
-
tm = calendar.
|
11037
|
+
tm = calendar.opt('theme') ? 'ui' : 'fc';
|
10679
11038
|
|
10680
11039
|
if (sections) {
|
10681
11040
|
if (!el) {
|
@@ -10706,6 +11065,8 @@ function Toolbar(calendar, toolbarOptions) {
|
|
10706
11065
|
function renderSection(position) {
|
10707
11066
|
var sectionEl = $('<div class="fc-' + position + '"/>');
|
10708
11067
|
var buttonStr = toolbarOptions.layout[position];
|
11068
|
+
var calendarCustomButtons = calendar.opt('customButtons') || {};
|
11069
|
+
var calendarButtonText = calendar.opt('buttonText') || {};
|
10709
11070
|
|
10710
11071
|
if (buttonStr) {
|
10711
11072
|
$.each(buttonStr.split(' '), function(i) {
|
@@ -10730,7 +11091,7 @@ function Toolbar(calendar, toolbarOptions) {
|
|
10730
11091
|
isOnlyButtons = false;
|
10731
11092
|
}
|
10732
11093
|
else {
|
10733
|
-
if ((customButtonProps =
|
11094
|
+
if ((customButtonProps = calendarCustomButtons[buttonName])) {
|
10734
11095
|
buttonClick = function(ev) {
|
10735
11096
|
if (customButtonProps.click) {
|
10736
11097
|
customButtonProps.click.call(button[0], ev);
|
@@ -10752,7 +11113,7 @@ function Toolbar(calendar, toolbarOptions) {
|
|
10752
11113
|
calendar[buttonName]();
|
10753
11114
|
};
|
10754
11115
|
overrideText = (calendar.overrides.buttonText || {})[buttonName];
|
10755
|
-
defaultText =
|
11116
|
+
defaultText = calendarButtonText[buttonName]; // everything else is considered default
|
10756
11117
|
}
|
10757
11118
|
|
10758
11119
|
if (buttonClick) {
|
@@ -10760,20 +11121,20 @@ function Toolbar(calendar, toolbarOptions) {
|
|
10760
11121
|
themeIcon =
|
10761
11122
|
customButtonProps ?
|
10762
11123
|
customButtonProps.themeIcon :
|
10763
|
-
calendar.
|
11124
|
+
calendar.opt('themeButtonIcons')[buttonName];
|
10764
11125
|
|
10765
11126
|
normalIcon =
|
10766
11127
|
customButtonProps ?
|
10767
11128
|
customButtonProps.icon :
|
10768
|
-
calendar.
|
11129
|
+
calendar.opt('buttonIcons')[buttonName];
|
10769
11130
|
|
10770
11131
|
if (overrideText) {
|
10771
11132
|
innerHtml = htmlEscape(overrideText);
|
10772
11133
|
}
|
10773
|
-
else if (themeIcon && calendar.
|
11134
|
+
else if (themeIcon && calendar.opt('theme')) {
|
10774
11135
|
innerHtml = "<span class='ui-icon ui-icon-" + themeIcon + "'></span>";
|
10775
11136
|
}
|
10776
|
-
else if (normalIcon && !calendar.
|
11137
|
+
else if (normalIcon && !calendar.opt('theme')) {
|
10777
11138
|
innerHtml = "<span class='fc-icon fc-icon-" + normalIcon + "'></span>";
|
10778
11139
|
}
|
10779
11140
|
else {
|
@@ -10914,24 +11275,31 @@ function Toolbar(calendar, toolbarOptions) {
|
|
10914
11275
|
|
10915
11276
|
;;
|
10916
11277
|
|
10917
|
-
var Calendar = FC.Calendar = Class.extend({
|
11278
|
+
var Calendar = FC.Calendar = Class.extend(EmitterMixin, {
|
10918
11279
|
|
10919
|
-
dirDefaults: null, // option defaults related to LTR or RTL
|
10920
|
-
localeDefaults: null, // option defaults related to current locale
|
10921
|
-
overrides: null, // option overrides given to the fullCalendar constructor
|
10922
|
-
dynamicOverrides: null, // options set with dynamic setter method. higher precedence than view overrides.
|
10923
|
-
options: null, // all defaults combined with overrides
|
10924
|
-
viewSpecCache: null, // cache of view definitions
|
10925
11280
|
view: null, // current View object
|
11281
|
+
viewsByType: null, // holds all instantiated view instances, current or not
|
10926
11282
|
currentDate: null, // unzoned moment. private (public API should use getDate instead)
|
10927
|
-
header: null,
|
10928
|
-
footer: null,
|
10929
11283
|
loadingLevel: 0, // number of simultaneous loading tasks
|
10930
11284
|
|
10931
11285
|
|
10932
|
-
|
10933
|
-
|
10934
|
-
|
11286
|
+
constructor: function(el, overrides) {
|
11287
|
+
|
11288
|
+
// declare the current calendar instance relies on GlobalEmitter. needed for garbage collection.
|
11289
|
+
// unneeded() is called in destroy.
|
11290
|
+
GlobalEmitter.needed();
|
11291
|
+
|
11292
|
+
this.el = el;
|
11293
|
+
this.viewsByType = {};
|
11294
|
+
this.viewSpecCache = {};
|
11295
|
+
|
11296
|
+
this.initOptionsInternals(overrides);
|
11297
|
+
this.initMomentInternals(); // needs to happen after options hash initialized
|
11298
|
+
this.initCurrentDate();
|
11299
|
+
|
11300
|
+
EventManager.call(this); // needs options immediately
|
11301
|
+
this.initialize();
|
11302
|
+
},
|
10935
11303
|
|
10936
11304
|
|
10937
11305
|
// Subclasses can override this for initialization logic after the constructor has been called
|
@@ -10939,199 +11307,35 @@ var Calendar = FC.Calendar = Class.extend({
|
|
10939
11307
|
},
|
10940
11308
|
|
10941
11309
|
|
10942
|
-
//
|
10943
|
-
//
|
10944
|
-
populateOptionsHash: function() {
|
10945
|
-
var locale, localeDefaults;
|
10946
|
-
var isRTL, dirDefaults;
|
11310
|
+
// Public API
|
11311
|
+
// -----------------------------------------------------------------------------------------------------------------
|
10947
11312
|
|
10948
|
-
locale = firstDefined( // explicit locale option given?
|
10949
|
-
this.dynamicOverrides.locale,
|
10950
|
-
this.overrides.locale
|
10951
|
-
);
|
10952
|
-
localeDefaults = localeOptionHash[locale];
|
10953
|
-
if (!localeDefaults) { // explicit locale option not given or invalid?
|
10954
|
-
locale = Calendar.defaults.locale;
|
10955
|
-
localeDefaults = localeOptionHash[locale] || {};
|
10956
|
-
}
|
10957
11313
|
|
10958
|
-
|
10959
|
-
|
10960
|
-
|
10961
|
-
localeDefaults.isRTL,
|
10962
|
-
Calendar.defaults.isRTL
|
10963
|
-
);
|
10964
|
-
dirDefaults = isRTL ? Calendar.rtlDefaults : {};
|
11314
|
+
getCalendar: function() {
|
11315
|
+
return this;
|
11316
|
+
},
|
10965
11317
|
|
10966
|
-
|
10967
|
-
|
10968
|
-
this.
|
10969
|
-
Calendar.defaults, // global defaults
|
10970
|
-
dirDefaults,
|
10971
|
-
localeDefaults,
|
10972
|
-
this.overrides,
|
10973
|
-
this.dynamicOverrides
|
10974
|
-
]);
|
10975
|
-
populateInstanceComputableOptions(this.options); // fill in gaps with computed options
|
11318
|
+
|
11319
|
+
getView: function() {
|
11320
|
+
return this.view;
|
10976
11321
|
},
|
10977
11322
|
|
10978
11323
|
|
10979
|
-
|
10980
|
-
|
10981
|
-
var
|
11324
|
+
publiclyTrigger: function(name, thisObj) {
|
11325
|
+
var args = Array.prototype.slice.call(arguments, 2);
|
11326
|
+
var optHandler = this.opt(name);
|
10982
11327
|
|
10983
|
-
|
11328
|
+
thisObj = thisObj || this.el[0];
|
11329
|
+
this.triggerWith(name, thisObj, args); // Emitter's method
|
11330
|
+
|
11331
|
+
if (optHandler) {
|
11332
|
+
return optHandler.apply(thisObj, args);
|
11333
|
+
}
|
10984
11334
|
},
|
10985
11335
|
|
10986
11336
|
|
10987
|
-
//
|
10988
|
-
//
|
10989
|
-
getUnitViewSpec: function(unit) {
|
10990
|
-
var viewTypes;
|
10991
|
-
var i;
|
10992
|
-
var spec;
|
10993
|
-
|
10994
|
-
if ($.inArray(unit, unitsDesc) != -1) {
|
10995
|
-
|
10996
|
-
// put views that have buttons first. there will be duplicates, but oh well
|
10997
|
-
viewTypes = this.header.getViewsWithButtons(); // TODO: include footer as well?
|
10998
|
-
$.each(FC.views, function(viewType) { // all views
|
10999
|
-
viewTypes.push(viewType);
|
11000
|
-
});
|
11001
|
-
|
11002
|
-
for (i = 0; i < viewTypes.length; i++) {
|
11003
|
-
spec = this.getViewSpec(viewTypes[i]);
|
11004
|
-
if (spec) {
|
11005
|
-
if (spec.singleUnit == unit) {
|
11006
|
-
return spec;
|
11007
|
-
}
|
11008
|
-
}
|
11009
|
-
}
|
11010
|
-
}
|
11011
|
-
},
|
11012
|
-
|
11013
|
-
|
11014
|
-
// Builds an object with information on how to create a given view
|
11015
|
-
buildViewSpec: function(requestedViewType) {
|
11016
|
-
var viewOverrides = this.overrides.views || {};
|
11017
|
-
var specChain = []; // for the view. lowest to highest priority
|
11018
|
-
var defaultsChain = []; // for the view. lowest to highest priority
|
11019
|
-
var overridesChain = []; // for the view. lowest to highest priority
|
11020
|
-
var viewType = requestedViewType;
|
11021
|
-
var spec; // for the view
|
11022
|
-
var overrides; // for the view
|
11023
|
-
var durationInput;
|
11024
|
-
var duration;
|
11025
|
-
var unit;
|
11026
|
-
|
11027
|
-
// iterate from the specific view definition to a more general one until we hit an actual View class
|
11028
|
-
while (viewType) {
|
11029
|
-
spec = fcViews[viewType];
|
11030
|
-
overrides = viewOverrides[viewType];
|
11031
|
-
viewType = null; // clear. might repopulate for another iteration
|
11032
|
-
|
11033
|
-
if (typeof spec === 'function') { // TODO: deprecate
|
11034
|
-
spec = { 'class': spec };
|
11035
|
-
}
|
11036
|
-
|
11037
|
-
if (spec) {
|
11038
|
-
specChain.unshift(spec);
|
11039
|
-
defaultsChain.unshift(spec.defaults || {});
|
11040
|
-
durationInput = durationInput || spec.duration;
|
11041
|
-
viewType = viewType || spec.type;
|
11042
|
-
}
|
11043
|
-
|
11044
|
-
if (overrides) {
|
11045
|
-
overridesChain.unshift(overrides); // view-specific option hashes have options at zero-level
|
11046
|
-
durationInput = durationInput || overrides.duration;
|
11047
|
-
viewType = viewType || overrides.type;
|
11048
|
-
}
|
11049
|
-
}
|
11050
|
-
|
11051
|
-
spec = mergeProps(specChain);
|
11052
|
-
spec.type = requestedViewType;
|
11053
|
-
if (!spec['class']) {
|
11054
|
-
return false;
|
11055
|
-
}
|
11056
|
-
|
11057
|
-
// fall back to top-level `duration` option
|
11058
|
-
durationInput = durationInput ||
|
11059
|
-
this.dynamicOverrides.duration ||
|
11060
|
-
this.overrides.duration;
|
11061
|
-
|
11062
|
-
if (durationInput) {
|
11063
|
-
duration = moment.duration(durationInput);
|
11064
|
-
|
11065
|
-
if (duration.valueOf()) { // valid?
|
11066
|
-
|
11067
|
-
unit = computeDurationGreatestUnit(duration, durationInput);
|
11068
|
-
|
11069
|
-
spec.duration = duration;
|
11070
|
-
spec.durationUnit = unit;
|
11071
|
-
|
11072
|
-
// view is a single-unit duration, like "week" or "day"
|
11073
|
-
// incorporate options for this. lowest priority
|
11074
|
-
if (duration.as(unit) === 1) {
|
11075
|
-
spec.singleUnit = unit;
|
11076
|
-
overridesChain.unshift(viewOverrides[unit] || {});
|
11077
|
-
}
|
11078
|
-
}
|
11079
|
-
}
|
11080
|
-
|
11081
|
-
spec.defaults = mergeOptions(defaultsChain);
|
11082
|
-
spec.overrides = mergeOptions(overridesChain);
|
11083
|
-
|
11084
|
-
this.buildViewSpecOptions(spec);
|
11085
|
-
this.buildViewSpecButtonText(spec, requestedViewType);
|
11086
|
-
|
11087
|
-
return spec;
|
11088
|
-
},
|
11089
|
-
|
11090
|
-
|
11091
|
-
// Builds and assigns a view spec's options object from its already-assigned defaults and overrides
|
11092
|
-
buildViewSpecOptions: function(spec) {
|
11093
|
-
spec.options = mergeOptions([ // lowest to highest priority
|
11094
|
-
Calendar.defaults, // global defaults
|
11095
|
-
spec.defaults, // view's defaults (from ViewSubclass.defaults)
|
11096
|
-
this.dirDefaults,
|
11097
|
-
this.localeDefaults, // locale and dir take precedence over view's defaults!
|
11098
|
-
this.overrides, // calendar's overrides (options given to constructor)
|
11099
|
-
spec.overrides, // view's overrides (view-specific options)
|
11100
|
-
this.dynamicOverrides // dynamically set via setter. highest precedence
|
11101
|
-
]);
|
11102
|
-
populateInstanceComputableOptions(spec.options);
|
11103
|
-
},
|
11104
|
-
|
11105
|
-
|
11106
|
-
// Computes and assigns a view spec's buttonText-related options
|
11107
|
-
buildViewSpecButtonText: function(spec, requestedViewType) {
|
11108
|
-
|
11109
|
-
// given an options object with a possible `buttonText` hash, lookup the buttonText for the
|
11110
|
-
// requested view, falling back to a generic unit entry like "week" or "day"
|
11111
|
-
function queryButtonText(options) {
|
11112
|
-
var buttonText = options.buttonText || {};
|
11113
|
-
return buttonText[requestedViewType] ||
|
11114
|
-
// view can decide to look up a certain key
|
11115
|
-
(spec.buttonTextKey ? buttonText[spec.buttonTextKey] : null) ||
|
11116
|
-
// a key like "month"
|
11117
|
-
(spec.singleUnit ? buttonText[spec.singleUnit] : null);
|
11118
|
-
}
|
11119
|
-
|
11120
|
-
// highest to lowest priority
|
11121
|
-
spec.buttonTextOverride =
|
11122
|
-
queryButtonText(this.dynamicOverrides) ||
|
11123
|
-
queryButtonText(this.overrides) || // constructor-specified buttonText lookup hash takes precedence
|
11124
|
-
spec.overrides.buttonText; // `buttonText` for view-specific options is a string
|
11125
|
-
|
11126
|
-
// highest to lowest priority. mirrors buildViewSpecOptions
|
11127
|
-
spec.buttonTextDefault =
|
11128
|
-
queryButtonText(this.localeDefaults) ||
|
11129
|
-
queryButtonText(this.dirDefaults) ||
|
11130
|
-
spec.defaults.buttonText || // a single string. from ViewSubclass.defaults
|
11131
|
-
queryButtonText(Calendar.defaults) ||
|
11132
|
-
(spec.duration ? this.humanizeDuration(spec.duration) : null) || // like "3 days"
|
11133
|
-
requestedViewType; // fall back to given view name
|
11134
|
-
},
|
11337
|
+
// View
|
11338
|
+
// -----------------------------------------------------------------------------------------------------------------
|
11135
11339
|
|
11136
11340
|
|
11137
11341
|
// Given a view name for a custom view or a standard view, creates a ready-to-go View object
|
@@ -11148,52 +11352,47 @@ var Calendar = FC.Calendar = Class.extend({
|
|
11148
11352
|
},
|
11149
11353
|
|
11150
11354
|
|
11151
|
-
|
11152
|
-
pushLoading: function() {
|
11153
|
-
if (!(this.loadingLevel++)) {
|
11154
|
-
this.publiclyTrigger('loading', null, true, this.view);
|
11155
|
-
}
|
11156
|
-
},
|
11355
|
+
changeView: function(viewName, dateOrRange) {
|
11157
11356
|
|
11357
|
+
if (dateOrRange) {
|
11158
11358
|
|
11159
|
-
|
11160
|
-
|
11161
|
-
|
11162
|
-
|
11359
|
+
if (dateOrRange.start && dateOrRange.end) { // a range
|
11360
|
+
this.recordOptionOverrides({ // will not rerender
|
11361
|
+
visibleRange: dateOrRange
|
11362
|
+
});
|
11363
|
+
}
|
11364
|
+
else { // a date
|
11365
|
+
this.currentDate = this.moment(dateOrRange).stripZone(); // just like gotoDate
|
11366
|
+
}
|
11163
11367
|
}
|
11368
|
+
|
11369
|
+
this.renderView(viewName);
|
11164
11370
|
},
|
11165
11371
|
|
11166
11372
|
|
11167
|
-
//
|
11168
|
-
|
11169
|
-
|
11170
|
-
var
|
11373
|
+
// Forces navigation to a view for the given date.
|
11374
|
+
// `viewType` can be a specific view name or a generic one like "week" or "day".
|
11375
|
+
zoomTo: function(newDate, viewType) {
|
11376
|
+
var spec;
|
11171
11377
|
|
11172
|
-
|
11173
|
-
|
11174
|
-
}
|
11175
|
-
else if (start.hasTime()) {
|
11176
|
-
end = start.clone().add(this.defaultTimedEventDuration);
|
11177
|
-
}
|
11178
|
-
else {
|
11179
|
-
end = start.clone().add(this.defaultAllDayEventDuration);
|
11180
|
-
}
|
11378
|
+
viewType = viewType || 'day'; // day is default zoom
|
11379
|
+
spec = this.getViewSpec(viewType) || this.getUnitViewSpec(viewType);
|
11181
11380
|
|
11182
|
-
|
11381
|
+
this.currentDate = newDate.clone();
|
11382
|
+
this.renderView(spec ? spec.type : null);
|
11183
11383
|
},
|
11184
11384
|
|
11185
11385
|
|
11186
11386
|
// Current Date
|
11187
|
-
//
|
11387
|
+
// -----------------------------------------------------------------------------------------------------------------
|
11188
11388
|
|
11189
11389
|
|
11190
|
-
/*
|
11191
|
-
Called before initialize()
|
11192
|
-
*/
|
11193
11390
|
initCurrentDate: function() {
|
11391
|
+
var defaultDateInput = this.opt('defaultDate');
|
11392
|
+
|
11194
11393
|
// compute the initial ambig-timezone date
|
11195
|
-
if (
|
11196
|
-
this.currentDate = this.moment(
|
11394
|
+
if (defaultDateInput != null) {
|
11395
|
+
this.currentDate = this.moment(defaultDateInput).stripZone();
|
11197
11396
|
}
|
11198
11397
|
else {
|
11199
11398
|
this.currentDate = this.getNow(); // getNow already returns unzoned
|
@@ -11201,24 +11400,6 @@ var Calendar = FC.Calendar = Class.extend({
|
|
11201
11400
|
},
|
11202
11401
|
|
11203
11402
|
|
11204
|
-
changeView: function(viewName, dateOrRange) {
|
11205
|
-
|
11206
|
-
if (dateOrRange) {
|
11207
|
-
|
11208
|
-
if (dateOrRange.start && dateOrRange.end) { // a range
|
11209
|
-
this.recordOptionOverrides({ // will not rerender
|
11210
|
-
visibleRange: dateOrRange
|
11211
|
-
});
|
11212
|
-
}
|
11213
|
-
else { // a date
|
11214
|
-
this.currentDate = this.moment(dateOrRange).stripZone(); // just like gotoDate
|
11215
|
-
}
|
11216
|
-
}
|
11217
|
-
|
11218
|
-
this.renderView(viewName);
|
11219
|
-
},
|
11220
|
-
|
11221
|
-
|
11222
11403
|
prev: function() {
|
11223
11404
|
var prevInfo = this.view.buildPrevDateProfile(this.currentDate);
|
11224
11405
|
|
@@ -11275,6 +11456,68 @@ var Calendar = FC.Calendar = Class.extend({
|
|
11275
11456
|
},
|
11276
11457
|
|
11277
11458
|
|
11459
|
+
// Loading Triggering
|
11460
|
+
// -----------------------------------------------------------------------------------------------------------------
|
11461
|
+
|
11462
|
+
|
11463
|
+
// Should be called when any type of async data fetching begins
|
11464
|
+
pushLoading: function() {
|
11465
|
+
if (!(this.loadingLevel++)) {
|
11466
|
+
this.publiclyTrigger('loading', null, true, this.view);
|
11467
|
+
}
|
11468
|
+
},
|
11469
|
+
|
11470
|
+
|
11471
|
+
// Should be called when any type of async data fetching completes
|
11472
|
+
popLoading: function() {
|
11473
|
+
if (!(--this.loadingLevel)) {
|
11474
|
+
this.publiclyTrigger('loading', null, false, this.view);
|
11475
|
+
}
|
11476
|
+
},
|
11477
|
+
|
11478
|
+
|
11479
|
+
// Selection
|
11480
|
+
// -----------------------------------------------------------------------------------------------------------------
|
11481
|
+
|
11482
|
+
|
11483
|
+
// this public method receives start/end dates in any format, with any timezone
|
11484
|
+
select: function(zonedStartInput, zonedEndInput) {
|
11485
|
+
this.view.select(
|
11486
|
+
this.buildSelectSpan.apply(this, arguments)
|
11487
|
+
);
|
11488
|
+
},
|
11489
|
+
|
11490
|
+
|
11491
|
+
unselect: function() { // safe to be called before renderView
|
11492
|
+
if (this.view) {
|
11493
|
+
this.view.unselect();
|
11494
|
+
}
|
11495
|
+
},
|
11496
|
+
|
11497
|
+
|
11498
|
+
// Given arguments to the select method in the API, returns a span (unzoned start/end and other info)
|
11499
|
+
buildSelectSpan: function(zonedStartInput, zonedEndInput) {
|
11500
|
+
var start = this.moment(zonedStartInput).stripZone();
|
11501
|
+
var end;
|
11502
|
+
|
11503
|
+
if (zonedEndInput) {
|
11504
|
+
end = this.moment(zonedEndInput).stripZone();
|
11505
|
+
}
|
11506
|
+
else if (start.hasTime()) {
|
11507
|
+
end = start.clone().add(this.defaultTimedEventDuration);
|
11508
|
+
}
|
11509
|
+
else {
|
11510
|
+
end = start.clone().add(this.defaultAllDayEventDuration);
|
11511
|
+
}
|
11512
|
+
|
11513
|
+
return { start: start, end: end };
|
11514
|
+
},
|
11515
|
+
|
11516
|
+
|
11517
|
+
// Misc
|
11518
|
+
// -----------------------------------------------------------------------------------------------------------------
|
11519
|
+
|
11520
|
+
|
11278
11521
|
// will return `null` if invalid range
|
11279
11522
|
parseRange: function(rangeInput) {
|
11280
11523
|
var start = null;
|
@@ -11297,122 +11540,247 @@ var Calendar = FC.Calendar = Class.extend({
|
|
11297
11540
|
}
|
11298
11541
|
|
11299
11542
|
return { start: start, end: end };
|
11300
|
-
}
|
11543
|
+
},
|
11301
11544
|
|
11302
|
-
});
|
11303
11545
|
|
11546
|
+
rerenderEvents: function() { // API method. destroys old events if previously rendered.
|
11547
|
+
if (this.elementVisible()) {
|
11548
|
+
this.reportEventChange(); // will re-trasmit events to the view, causing a rerender
|
11549
|
+
}
|
11550
|
+
}
|
11304
11551
|
|
11305
|
-
|
11552
|
+
});
|
11306
11553
|
|
11554
|
+
;;
|
11555
|
+
/*
|
11556
|
+
Options binding/triggering system.
|
11557
|
+
*/
|
11558
|
+
Calendar.mixin({
|
11307
11559
|
|
11308
|
-
|
11309
|
-
|
11560
|
+
dirDefaults: null, // option defaults related to LTR or RTL
|
11561
|
+
localeDefaults: null, // option defaults related to current locale
|
11562
|
+
overrides: null, // option overrides given to the fullCalendar constructor
|
11563
|
+
dynamicOverrides: null, // options set with dynamic setter method. higher precedence than view overrides.
|
11564
|
+
optionsModel: null, // all defaults combined with overrides
|
11310
11565
|
|
11311
|
-
// declare the current calendar instance relies on GlobalEmitter. needed for garbage collection.
|
11312
|
-
GlobalEmitter.needed();
|
11313
11566
|
|
11567
|
+
initOptionsInternals: function(overrides) {
|
11568
|
+
this.overrides = $.extend({}, overrides); // make a copy
|
11569
|
+
this.dynamicOverrides = {};
|
11570
|
+
this.optionsModel = new Model();
|
11314
11571
|
|
11315
|
-
|
11316
|
-
|
11572
|
+
this.populateOptionsHash();
|
11573
|
+
},
|
11317
11574
|
|
11318
|
-
t.render = render;
|
11319
|
-
t.destroy = destroy;
|
11320
|
-
t.rerenderEvents = rerenderEvents;
|
11321
|
-
t.select = select;
|
11322
|
-
t.unselect = unselect;
|
11323
|
-
t.zoomTo = zoomTo;
|
11324
|
-
t.getCalendar = getCalendar;
|
11325
|
-
t.getView = getView;
|
11326
|
-
t.option = option; // getter/setter method
|
11327
|
-
t.recordOptionOverrides = recordOptionOverrides;
|
11328
|
-
t.publiclyTrigger = publiclyTrigger;
|
11329
|
-
|
11330
|
-
|
11331
|
-
// Options
|
11332
|
-
// -----------------------------------------------------------------------------------
|
11333
11575
|
|
11334
|
-
|
11335
|
-
|
11336
|
-
|
11337
|
-
t.overrides = $.extend({}, overrides); // make a copy
|
11576
|
+
// public getter/setter
|
11577
|
+
option: function(name, value) {
|
11578
|
+
var newOptionHash;
|
11338
11579
|
|
11339
|
-
|
11580
|
+
if (typeof name === 'string') {
|
11581
|
+
if (value === undefined) { // getter
|
11582
|
+
return this.optionsModel.get(name);
|
11583
|
+
}
|
11584
|
+
else { // setter for individual option
|
11585
|
+
newOptionHash = {};
|
11586
|
+
newOptionHash[name] = value;
|
11587
|
+
this.setOptions(newOptionHash);
|
11588
|
+
}
|
11589
|
+
}
|
11590
|
+
else if (typeof name === 'object') { // compound setter with object input
|
11591
|
+
this.setOptions(name);
|
11592
|
+
}
|
11593
|
+
},
|
11340
11594
|
|
11341
11595
|
|
11596
|
+
// private getter
|
11597
|
+
opt: function(name) {
|
11598
|
+
return this.optionsModel.get(name);
|
11599
|
+
},
|
11342
11600
|
|
11343
|
-
// Locale-data Internals
|
11344
|
-
// -----------------------------------------------------------------------------------
|
11345
|
-
// Apply overrides to the current locale's data
|
11346
11601
|
|
11347
|
-
|
11602
|
+
setOptions: function(newOptionHash) {
|
11603
|
+
var optionCnt = 0;
|
11604
|
+
var optionName;
|
11348
11605
|
|
11349
|
-
|
11350
|
-
// Happens before any internal objects rebuild or rerender, because this is very core.
|
11351
|
-
t.bindOptions([
|
11352
|
-
'locale', 'monthNames', 'monthNamesShort', 'dayNames', 'dayNamesShort', 'firstDay', 'weekNumberCalculation'
|
11353
|
-
], function(locale, monthNames, monthNamesShort, dayNames, dayNamesShort, firstDay, weekNumberCalculation) {
|
11606
|
+
this.recordOptionOverrides(newOptionHash);
|
11354
11607
|
|
11355
|
-
|
11356
|
-
|
11357
|
-
weekNumberCalculation = 'ISO'; // normalize
|
11608
|
+
for (optionName in newOptionHash) {
|
11609
|
+
optionCnt++;
|
11358
11610
|
}
|
11359
11611
|
|
11360
|
-
|
11361
|
-
|
11362
|
-
)
|
11363
|
-
|
11364
|
-
|
11365
|
-
|
11366
|
-
|
11367
|
-
|
11368
|
-
|
11369
|
-
|
11370
|
-
|
11371
|
-
|
11372
|
-
|
11373
|
-
|
11374
|
-
|
11612
|
+
// special-case handling of single option change.
|
11613
|
+
// if only one option change, `optionName` will be its name.
|
11614
|
+
if (optionCnt === 1) {
|
11615
|
+
if (optionName === 'height' || optionName === 'contentHeight' || optionName === 'aspectRatio') {
|
11616
|
+
this.updateSize(true); // true = allow recalculation of height
|
11617
|
+
return;
|
11618
|
+
}
|
11619
|
+
else if (optionName === 'defaultDate') {
|
11620
|
+
return; // can't change date this way. use gotoDate instead
|
11621
|
+
}
|
11622
|
+
else if (optionName === 'businessHours') {
|
11623
|
+
if (this.view) {
|
11624
|
+
this.view.unrenderBusinessHours();
|
11625
|
+
this.view.renderBusinessHours();
|
11626
|
+
}
|
11627
|
+
return;
|
11628
|
+
}
|
11629
|
+
else if (optionName === 'timezone') {
|
11630
|
+
this.rezoneArrayEventSources();
|
11631
|
+
this.refetchEvents();
|
11632
|
+
return;
|
11633
|
+
}
|
11375
11634
|
}
|
11376
11635
|
|
11377
|
-
|
11378
|
-
|
11379
|
-
|
11380
|
-
if (firstDay != null) {
|
11381
|
-
var _week = createObject(localeData._week); // _week: { dow: # }
|
11382
|
-
_week.dow = firstDay;
|
11383
|
-
localeData._week = _week;
|
11384
|
-
}
|
11636
|
+
// catch-all. rerender the header and footer and rebuild/rerender the current view
|
11637
|
+
this.renderHeader();
|
11638
|
+
this.renderFooter();
|
11385
11639
|
|
11386
|
-
|
11387
|
-
|
11388
|
-
|
11389
|
-
|
11390
|
-
)
|
11391
|
-
|
11640
|
+
// even non-current views will be affected by this option change. do before rerender
|
11641
|
+
// TODO: detangle
|
11642
|
+
this.viewsByType = {};
|
11643
|
+
|
11644
|
+
this.reinitView();
|
11645
|
+
},
|
11646
|
+
|
11647
|
+
|
11648
|
+
// Computes the flattened options hash for the calendar and assigns to `this.options`.
|
11649
|
+
// Assumes this.overrides and this.dynamicOverrides have already been initialized.
|
11650
|
+
populateOptionsHash: function() {
|
11651
|
+
var locale, localeDefaults;
|
11652
|
+
var isRTL, dirDefaults;
|
11653
|
+
var rawOptions;
|
11654
|
+
|
11655
|
+
locale = firstDefined( // explicit locale option given?
|
11656
|
+
this.dynamicOverrides.locale,
|
11657
|
+
this.overrides.locale
|
11658
|
+
);
|
11659
|
+
localeDefaults = localeOptionHash[locale];
|
11660
|
+
if (!localeDefaults) { // explicit locale option not given or invalid?
|
11661
|
+
locale = Calendar.defaults.locale;
|
11662
|
+
localeDefaults = localeOptionHash[locale] || {};
|
11392
11663
|
}
|
11393
11664
|
|
11394
|
-
|
11395
|
-
|
11396
|
-
|
11397
|
-
|
11665
|
+
isRTL = firstDefined( // based on options computed so far, is direction RTL?
|
11666
|
+
this.dynamicOverrides.isRTL,
|
11667
|
+
this.overrides.isRTL,
|
11668
|
+
localeDefaults.isRTL,
|
11669
|
+
Calendar.defaults.isRTL
|
11670
|
+
);
|
11671
|
+
dirDefaults = isRTL ? Calendar.rtlDefaults : {};
|
11672
|
+
|
11673
|
+
this.dirDefaults = dirDefaults;
|
11674
|
+
this.localeDefaults = localeDefaults;
|
11675
|
+
|
11676
|
+
rawOptions = mergeOptions([ // merge defaults and overrides. lowest to highest precedence
|
11677
|
+
Calendar.defaults, // global defaults
|
11678
|
+
dirDefaults,
|
11679
|
+
localeDefaults,
|
11680
|
+
this.overrides,
|
11681
|
+
this.dynamicOverrides
|
11682
|
+
]);
|
11683
|
+
populateInstanceComputableOptions(rawOptions); // fill in gaps with computed options
|
11684
|
+
|
11685
|
+
this.optionsModel.reset(rawOptions);
|
11686
|
+
},
|
11687
|
+
|
11688
|
+
|
11689
|
+
// stores the new options internally, but does not rerender anything.
|
11690
|
+
recordOptionOverrides: function(newOptionHash) {
|
11691
|
+
var optionName;
|
11692
|
+
|
11693
|
+
for (optionName in newOptionHash) {
|
11694
|
+
this.dynamicOverrides[optionName] = newOptionHash[optionName];
|
11398
11695
|
}
|
11399
|
-
});
|
11400
11696
|
|
11697
|
+
this.viewSpecCache = {}; // the dynamic override invalidates the options in this cache, so just clear it
|
11698
|
+
this.populateOptionsHash(); // this.options needs to be recomputed after the dynamic override
|
11699
|
+
}
|
11401
11700
|
|
11402
|
-
|
11403
|
-
|
11701
|
+
});
|
11702
|
+
|
11703
|
+
;;
|
11704
|
+
|
11705
|
+
Calendar.mixin({
|
11706
|
+
|
11707
|
+
defaultAllDayEventDuration: null,
|
11708
|
+
defaultTimedEventDuration: null,
|
11709
|
+
localeData: null,
|
11710
|
+
|
11711
|
+
|
11712
|
+
initMomentInternals: function() {
|
11713
|
+
var _this = this;
|
11404
11714
|
|
11715
|
+
this.defaultAllDayEventDuration = moment.duration(this.opt('defaultAllDayEventDuration'));
|
11716
|
+
this.defaultTimedEventDuration = moment.duration(this.opt('defaultTimedEventDuration'));
|
11405
11717
|
|
11406
|
-
|
11407
|
-
|
11718
|
+
// Called immediately, and when any of the options change.
|
11719
|
+
// Happens before any internal objects rebuild or rerender, because this is very core.
|
11720
|
+
this.optionsModel.watch('buildingMomentLocale', [
|
11721
|
+
'?locale', '?monthNames', '?monthNamesShort', '?dayNames', '?dayNamesShort',
|
11722
|
+
'?firstDay', '?weekNumberCalculation'
|
11723
|
+
], function(opts) {
|
11724
|
+
var weekNumberCalculation = opts.weekNumberCalculation;
|
11725
|
+
var firstDay = opts.firstDay;
|
11726
|
+
var _week;
|
11727
|
+
|
11728
|
+
// normalize
|
11729
|
+
if (weekNumberCalculation === 'iso') {
|
11730
|
+
weekNumberCalculation = 'ISO'; // normalize
|
11731
|
+
}
|
11732
|
+
|
11733
|
+
var localeData = createObject( // make a cheap copy
|
11734
|
+
getMomentLocaleData(opts.locale) // will fall back to en
|
11735
|
+
);
|
11736
|
+
|
11737
|
+
if (opts.monthNames) {
|
11738
|
+
localeData._months = opts.monthNames;
|
11739
|
+
}
|
11740
|
+
if (opts.monthNamesShort) {
|
11741
|
+
localeData._monthsShort = opts.monthNamesShort;
|
11742
|
+
}
|
11743
|
+
if (opts.dayNames) {
|
11744
|
+
localeData._weekdays = opts.dayNames;
|
11745
|
+
}
|
11746
|
+
if (opts.dayNamesShort) {
|
11747
|
+
localeData._weekdaysShort = opts.dayNamesShort;
|
11748
|
+
}
|
11749
|
+
|
11750
|
+
if (firstDay == null && weekNumberCalculation === 'ISO') {
|
11751
|
+
firstDay = 1;
|
11752
|
+
}
|
11753
|
+
if (firstDay != null) {
|
11754
|
+
_week = createObject(localeData._week); // _week: { dow: # }
|
11755
|
+
_week.dow = firstDay;
|
11756
|
+
localeData._week = _week;
|
11757
|
+
}
|
11758
|
+
|
11759
|
+
if ( // whitelist certain kinds of input
|
11760
|
+
weekNumberCalculation === 'ISO' ||
|
11761
|
+
weekNumberCalculation === 'local' ||
|
11762
|
+
typeof weekNumberCalculation === 'function'
|
11763
|
+
) {
|
11764
|
+
localeData._fullCalendar_weekCalc = weekNumberCalculation; // moment-ext will know what to do with it
|
11765
|
+
}
|
11766
|
+
|
11767
|
+
_this.localeData = localeData;
|
11768
|
+
|
11769
|
+
// If the internal current date object already exists, move to new locale.
|
11770
|
+
// We do NOT need to do this technique for event dates, because this happens when converting to "segments".
|
11771
|
+
if (_this.currentDate) {
|
11772
|
+
_this.localizeMoment(_this.currentDate); // sets to localeData
|
11773
|
+
}
|
11774
|
+
});
|
11775
|
+
},
|
11408
11776
|
|
11409
11777
|
|
11410
11778
|
// Builds a moment using the settings of the current calendar: timezone and locale.
|
11411
11779
|
// Accepts anything the vanilla moment() constructor accepts.
|
11412
|
-
|
11780
|
+
moment: function() {
|
11413
11781
|
var mom;
|
11414
11782
|
|
11415
|
-
if (
|
11783
|
+
if (this.opt('timezone') === 'local') {
|
11416
11784
|
mom = FC.moment.apply(null, arguments);
|
11417
11785
|
|
11418
11786
|
// Force the moment to be local, because FC.moment doesn't guarantee it.
|
@@ -11420,40 +11788,39 @@ function Calendar_constructor(element, overrides) {
|
|
11420
11788
|
mom.local();
|
11421
11789
|
}
|
11422
11790
|
}
|
11423
|
-
else if (
|
11791
|
+
else if (this.opt('timezone') === 'UTC') {
|
11424
11792
|
mom = FC.moment.utc.apply(null, arguments); // process as UTC
|
11425
11793
|
}
|
11426
11794
|
else {
|
11427
11795
|
mom = FC.moment.parseZone.apply(null, arguments); // let the input decide the zone
|
11428
11796
|
}
|
11429
11797
|
|
11430
|
-
localizeMoment(mom);
|
11798
|
+
this.localizeMoment(mom); // TODO
|
11431
11799
|
|
11432
11800
|
return mom;
|
11433
|
-
}
|
11801
|
+
},
|
11434
11802
|
|
11435
11803
|
|
11436
11804
|
// Updates the given moment's locale settings to the current calendar locale settings.
|
11437
|
-
function
|
11438
|
-
mom._locale = localeData;
|
11439
|
-
}
|
11440
|
-
t.localizeMoment = localizeMoment;
|
11805
|
+
localizeMoment: function(mom) {
|
11806
|
+
mom._locale = this.localeData;
|
11807
|
+
},
|
11441
11808
|
|
11442
11809
|
|
11443
11810
|
// Returns a boolean about whether or not the calendar knows how to calculate
|
11444
11811
|
// the timezone offset of arbitrary dates in the current timezone.
|
11445
|
-
|
11446
|
-
return
|
11447
|
-
}
|
11812
|
+
getIsAmbigTimezone: function() {
|
11813
|
+
return this.opt('timezone') !== 'local' && this.opt('timezone') !== 'UTC';
|
11814
|
+
},
|
11448
11815
|
|
11449
11816
|
|
11450
11817
|
// Returns a copy of the given date in the current timezone. Has no effect on dates without times.
|
11451
|
-
|
11818
|
+
applyTimezone: function(date) {
|
11452
11819
|
if (!date.hasTime()) {
|
11453
11820
|
return date.clone();
|
11454
11821
|
}
|
11455
11822
|
|
11456
|
-
var zonedDate =
|
11823
|
+
var zonedDate = this.moment(date.toArray());
|
11457
11824
|
var timeAdjust = date.time() - zonedDate.time();
|
11458
11825
|
var adjustedZonedDate;
|
11459
11826
|
|
@@ -11466,115 +11833,268 @@ function Calendar_constructor(element, overrides) {
|
|
11466
11833
|
}
|
11467
11834
|
|
11468
11835
|
return zonedDate;
|
11469
|
-
}
|
11836
|
+
},
|
11470
11837
|
|
11471
11838
|
|
11472
11839
|
// Returns a moment for the current date, as defined by the client's computer or from the `now` option.
|
11473
11840
|
// Will return an moment with an ambiguous timezone.
|
11474
|
-
|
11475
|
-
var now =
|
11841
|
+
getNow: function() {
|
11842
|
+
var now = this.opt('now');
|
11476
11843
|
if (typeof now === 'function') {
|
11477
11844
|
now = now();
|
11478
11845
|
}
|
11479
|
-
return
|
11480
|
-
}
|
11846
|
+
return this.moment(now).stripZone();
|
11847
|
+
},
|
11848
|
+
|
11849
|
+
|
11850
|
+
// Produces a human-readable string for the given duration.
|
11851
|
+
// Side-effect: changes the locale of the given duration.
|
11852
|
+
humanizeDuration: function(duration) {
|
11853
|
+
return duration.locale(this.opt('locale')).humanize();
|
11854
|
+
},
|
11855
|
+
|
11856
|
+
|
11857
|
+
|
11858
|
+
// Event-Specific Date Utilities. TODO: move
|
11859
|
+
// -----------------------------------------------------------------------------------------------------------------
|
11481
11860
|
|
11482
11861
|
|
11483
11862
|
// Get an event's normalized end date. If not present, calculate it from the defaults.
|
11484
|
-
|
11863
|
+
getEventEnd: function(event) {
|
11485
11864
|
if (event.end) {
|
11486
11865
|
return event.end.clone();
|
11487
11866
|
}
|
11488
11867
|
else {
|
11489
|
-
return
|
11868
|
+
return this.getDefaultEventEnd(event.allDay, event.start);
|
11490
11869
|
}
|
11491
|
-
}
|
11870
|
+
},
|
11492
11871
|
|
11493
11872
|
|
11494
11873
|
// Given an event's allDay status and start date, return what its fallback end date should be.
|
11495
11874
|
// TODO: rename to computeDefaultEventEnd
|
11496
|
-
|
11875
|
+
getDefaultEventEnd: function(allDay, zonedStart) {
|
11497
11876
|
var end = zonedStart.clone();
|
11498
11877
|
|
11499
11878
|
if (allDay) {
|
11500
|
-
end.stripTime().add(
|
11879
|
+
end.stripTime().add(this.defaultAllDayEventDuration);
|
11501
11880
|
}
|
11502
11881
|
else {
|
11503
|
-
end.add(
|
11882
|
+
end.add(this.defaultTimedEventDuration);
|
11504
11883
|
}
|
11505
11884
|
|
11506
|
-
if (
|
11885
|
+
if (this.getIsAmbigTimezone()) {
|
11507
11886
|
end.stripZone(); // we don't know what the tzo should be
|
11508
11887
|
}
|
11509
11888
|
|
11510
11889
|
return end;
|
11511
|
-
}
|
11890
|
+
}
|
11512
11891
|
|
11892
|
+
});
|
11513
11893
|
|
11514
|
-
|
11515
|
-
// Side-effect: changes the locale of the given duration.
|
11516
|
-
t.humanizeDuration = function(duration) {
|
11517
|
-
return duration.locale(t.options.locale).humanize();
|
11518
|
-
};
|
11894
|
+
;;
|
11519
11895
|
|
11896
|
+
Calendar.mixin({
|
11520
11897
|
|
11898
|
+
viewSpecCache: null, // cache of view definitions (initialized in Calendar.js)
|
11521
11899
|
|
11522
|
-
|
11523
|
-
//
|
11900
|
+
|
11901
|
+
// Gets information about how to create a view. Will use a cache.
|
11902
|
+
getViewSpec: function(viewType) {
|
11903
|
+
var cache = this.viewSpecCache;
|
11904
|
+
|
11905
|
+
return cache[viewType] || (cache[viewType] = this.buildViewSpec(viewType));
|
11906
|
+
},
|
11524
11907
|
|
11525
11908
|
|
11526
|
-
|
11909
|
+
// Given a duration singular unit, like "week" or "day", finds a matching view spec.
|
11910
|
+
// Preference is given to views that have corresponding buttons.
|
11911
|
+
getUnitViewSpec: function(unit) {
|
11912
|
+
var viewTypes;
|
11913
|
+
var i;
|
11914
|
+
var spec;
|
11527
11915
|
|
11916
|
+
if ($.inArray(unit, unitsDesc) != -1) {
|
11528
11917
|
|
11918
|
+
// put views that have buttons first. there will be duplicates, but oh well
|
11919
|
+
viewTypes = this.header.getViewsWithButtons(); // TODO: include footer as well?
|
11920
|
+
$.each(FC.views, function(viewType) { // all views
|
11921
|
+
viewTypes.push(viewType);
|
11922
|
+
});
|
11529
11923
|
|
11530
|
-
|
11531
|
-
|
11924
|
+
for (i = 0; i < viewTypes.length; i++) {
|
11925
|
+
spec = this.getViewSpec(viewTypes[i]);
|
11926
|
+
if (spec) {
|
11927
|
+
if (spec.singleUnit == unit) {
|
11928
|
+
return spec;
|
11929
|
+
}
|
11930
|
+
}
|
11931
|
+
}
|
11932
|
+
}
|
11933
|
+
},
|
11934
|
+
|
11935
|
+
|
11936
|
+
// Builds an object with information on how to create a given view
|
11937
|
+
buildViewSpec: function(requestedViewType) {
|
11938
|
+
var viewOverrides = this.overrides.views || {};
|
11939
|
+
var specChain = []; // for the view. lowest to highest priority
|
11940
|
+
var defaultsChain = []; // for the view. lowest to highest priority
|
11941
|
+
var overridesChain = []; // for the view. lowest to highest priority
|
11942
|
+
var viewType = requestedViewType;
|
11943
|
+
var spec; // for the view
|
11944
|
+
var overrides; // for the view
|
11945
|
+
var durationInput;
|
11946
|
+
var duration;
|
11947
|
+
var unit;
|
11948
|
+
|
11949
|
+
// iterate from the specific view definition to a more general one until we hit an actual View class
|
11950
|
+
while (viewType) {
|
11951
|
+
spec = fcViews[viewType];
|
11952
|
+
overrides = viewOverrides[viewType];
|
11953
|
+
viewType = null; // clear. might repopulate for another iteration
|
11532
11954
|
|
11955
|
+
if (typeof spec === 'function') { // TODO: deprecate
|
11956
|
+
spec = { 'class': spec };
|
11957
|
+
}
|
11958
|
+
|
11959
|
+
if (spec) {
|
11960
|
+
specChain.unshift(spec);
|
11961
|
+
defaultsChain.unshift(spec.defaults || {});
|
11962
|
+
durationInput = durationInput || spec.duration;
|
11963
|
+
viewType = viewType || spec.type;
|
11964
|
+
}
|
11965
|
+
|
11966
|
+
if (overrides) {
|
11967
|
+
overridesChain.unshift(overrides); // view-specific option hashes have options at zero-level
|
11968
|
+
durationInput = durationInput || overrides.duration;
|
11969
|
+
viewType = viewType || overrides.type;
|
11970
|
+
}
|
11971
|
+
}
|
11972
|
+
|
11973
|
+
spec = mergeProps(specChain);
|
11974
|
+
spec.type = requestedViewType;
|
11975
|
+
if (!spec['class']) {
|
11976
|
+
return false;
|
11977
|
+
}
|
11978
|
+
|
11979
|
+
// fall back to top-level `duration` option
|
11980
|
+
durationInput = durationInput ||
|
11981
|
+
this.dynamicOverrides.duration ||
|
11982
|
+
this.overrides.duration;
|
11983
|
+
|
11984
|
+
if (durationInput) {
|
11985
|
+
duration = moment.duration(durationInput);
|
11986
|
+
|
11987
|
+
if (duration.valueOf()) { // valid?
|
11988
|
+
|
11989
|
+
unit = computeDurationGreatestUnit(duration, durationInput);
|
11990
|
+
|
11991
|
+
spec.duration = duration;
|
11992
|
+
spec.durationUnit = unit;
|
11993
|
+
|
11994
|
+
// view is a single-unit duration, like "week" or "day"
|
11995
|
+
// incorporate options for this. lowest priority
|
11996
|
+
if (duration.as(unit) === 1) {
|
11997
|
+
spec.singleUnit = unit;
|
11998
|
+
overridesChain.unshift(viewOverrides[unit] || {});
|
11999
|
+
}
|
12000
|
+
}
|
12001
|
+
}
|
12002
|
+
|
12003
|
+
spec.defaults = mergeOptions(defaultsChain);
|
12004
|
+
spec.overrides = mergeOptions(overridesChain);
|
12005
|
+
|
12006
|
+
this.buildViewSpecOptions(spec);
|
12007
|
+
this.buildViewSpecButtonText(spec, requestedViewType);
|
12008
|
+
|
12009
|
+
return spec;
|
12010
|
+
},
|
12011
|
+
|
12012
|
+
|
12013
|
+
// Builds and assigns a view spec's options object from its already-assigned defaults and overrides
|
12014
|
+
buildViewSpecOptions: function(spec) {
|
12015
|
+
spec.options = mergeOptions([ // lowest to highest priority
|
12016
|
+
Calendar.defaults, // global defaults
|
12017
|
+
spec.defaults, // view's defaults (from ViewSubclass.defaults)
|
12018
|
+
this.dirDefaults,
|
12019
|
+
this.localeDefaults, // locale and dir take precedence over view's defaults!
|
12020
|
+
this.overrides, // calendar's overrides (options given to constructor)
|
12021
|
+
spec.overrides, // view's overrides (view-specific options)
|
12022
|
+
this.dynamicOverrides // dynamically set via setter. highest precedence
|
12023
|
+
]);
|
12024
|
+
populateInstanceComputableOptions(spec.options);
|
12025
|
+
},
|
12026
|
+
|
12027
|
+
|
12028
|
+
// Computes and assigns a view spec's buttonText-related options
|
12029
|
+
buildViewSpecButtonText: function(spec, requestedViewType) {
|
12030
|
+
|
12031
|
+
// given an options object with a possible `buttonText` hash, lookup the buttonText for the
|
12032
|
+
// requested view, falling back to a generic unit entry like "week" or "day"
|
12033
|
+
function queryButtonText(options) {
|
12034
|
+
var buttonText = options.buttonText || {};
|
12035
|
+
return buttonText[requestedViewType] ||
|
12036
|
+
// view can decide to look up a certain key
|
12037
|
+
(spec.buttonTextKey ? buttonText[spec.buttonTextKey] : null) ||
|
12038
|
+
// a key like "month"
|
12039
|
+
(spec.singleUnit ? buttonText[spec.singleUnit] : null);
|
12040
|
+
}
|
12041
|
+
|
12042
|
+
// highest to lowest priority
|
12043
|
+
spec.buttonTextOverride =
|
12044
|
+
queryButtonText(this.dynamicOverrides) ||
|
12045
|
+
queryButtonText(this.overrides) || // constructor-specified buttonText lookup hash takes precedence
|
12046
|
+
spec.overrides.buttonText; // `buttonText` for view-specific options is a string
|
11533
12047
|
|
11534
|
-
|
11535
|
-
|
11536
|
-
|
11537
|
-
|
11538
|
-
|
11539
|
-
|
11540
|
-
|
11541
|
-
|
11542
|
-
|
11543
|
-
var windowResizeProxy; // wraps the windowResize function
|
11544
|
-
var ignoreWindowResize = 0;
|
12048
|
+
// highest to lowest priority. mirrors buildViewSpecOptions
|
12049
|
+
spec.buttonTextDefault =
|
12050
|
+
queryButtonText(this.localeDefaults) ||
|
12051
|
+
queryButtonText(this.dirDefaults) ||
|
12052
|
+
spec.defaults.buttonText || // a single string. from ViewSubclass.defaults
|
12053
|
+
queryButtonText(Calendar.defaults) ||
|
12054
|
+
(spec.duration ? this.humanizeDuration(spec.duration) : null) || // like "3 days"
|
12055
|
+
requestedViewType; // fall back to given view name
|
12056
|
+
}
|
11545
12057
|
|
12058
|
+
});
|
11546
12059
|
|
11547
|
-
|
12060
|
+
;;
|
11548
12061
|
|
12062
|
+
Calendar.mixin({
|
11549
12063
|
|
11550
|
-
|
11551
|
-
|
12064
|
+
el: null,
|
12065
|
+
contentEl: null,
|
12066
|
+
suggestedViewHeight: null,
|
12067
|
+
windowResizeProxy: null,
|
12068
|
+
ignoreWindowResize: 0,
|
11552
12069
|
|
11553
12070
|
|
11554
|
-
function
|
11555
|
-
if (!
|
11556
|
-
initialRender();
|
12071
|
+
render: function() {
|
12072
|
+
if (!this.contentEl) {
|
12073
|
+
this.initialRender();
|
11557
12074
|
}
|
11558
|
-
else if (elementVisible()) {
|
12075
|
+
else if (this.elementVisible()) {
|
11559
12076
|
// mainly for the public API
|
11560
|
-
calcSize();
|
11561
|
-
renderView();
|
12077
|
+
this.calcSize();
|
12078
|
+
this.renderView();
|
11562
12079
|
}
|
11563
|
-
}
|
12080
|
+
},
|
12081
|
+
|
11564
12082
|
|
12083
|
+
initialRender: function() {
|
12084
|
+
var _this = this;
|
12085
|
+
var el = this.el;
|
11565
12086
|
|
11566
|
-
|
11567
|
-
element.addClass('fc');
|
12087
|
+
el.addClass('fc');
|
11568
12088
|
|
11569
12089
|
// event delegation for nav links
|
11570
|
-
|
12090
|
+
el.on('click.fc', 'a[data-goto]', function(ev) {
|
11571
12091
|
var anchorEl = $(this);
|
11572
12092
|
var gotoOptions = anchorEl.data('goto'); // will automatically parse JSON
|
11573
|
-
var date =
|
12093
|
+
var date = _this.moment(gotoOptions.date);
|
11574
12094
|
var viewType = gotoOptions.type;
|
11575
12095
|
|
11576
12096
|
// property like "navLinkDayClick". might be a string or a function
|
11577
|
-
var customAction =
|
12097
|
+
var customAction = _this.view.opt('navLink' + capitaliseFirstLetter(viewType) + 'Click');
|
11578
12098
|
|
11579
12099
|
if (typeof customAction === 'function') {
|
11580
12100
|
customAction(date, ev);
|
@@ -11583,69 +12103,68 @@ function Calendar_constructor(element, overrides) {
|
|
11583
12103
|
if (typeof customAction === 'string') {
|
11584
12104
|
viewType = customAction;
|
11585
12105
|
}
|
11586
|
-
zoomTo(date, viewType);
|
12106
|
+
_this.zoomTo(date, viewType);
|
11587
12107
|
}
|
11588
12108
|
});
|
11589
12109
|
|
11590
12110
|
// called immediately, and upon option change
|
11591
|
-
|
11592
|
-
|
11593
|
-
|
11594
|
-
element.toggleClass('fc-unthemed', !theme);
|
12111
|
+
this.optionsModel.watch('applyingThemeClasses', [ '?theme' ], function(opts) {
|
12112
|
+
el.toggleClass('ui-widget', opts.theme);
|
12113
|
+
el.toggleClass('fc-unthemed', !opts.theme);
|
11595
12114
|
});
|
11596
12115
|
|
11597
12116
|
// called immediately, and upon option change.
|
11598
12117
|
// HACK: locale often affects isRTL, so we explicitly listen to that too.
|
11599
|
-
|
11600
|
-
|
11601
|
-
|
12118
|
+
this.optionsModel.watch('applyingDirClasses', [ '?isRTL', '?locale' ], function(opts) {
|
12119
|
+
el.toggleClass('fc-ltr', !opts.isRTL);
|
12120
|
+
el.toggleClass('fc-rtl', opts.isRTL);
|
11602
12121
|
});
|
11603
12122
|
|
11604
|
-
|
12123
|
+
this.contentEl = $("<div class='fc-view-container'/>").prependTo(el);
|
11605
12124
|
|
11606
|
-
|
11607
|
-
|
12125
|
+
this.initToolbars();
|
12126
|
+
this.renderHeader();
|
12127
|
+
this.renderFooter();
|
12128
|
+
this.renderView(this.opt('defaultView'));
|
11608
12129
|
|
11609
|
-
|
11610
|
-
|
11611
|
-
|
11612
|
-
|
11613
|
-
|
11614
|
-
|
11615
|
-
|
11616
|
-
if (t.options.handleWindowResize) {
|
11617
|
-
windowResizeProxy = debounce(windowResize, t.options.windowResizeDelay); // prevents rapid calls
|
11618
|
-
$(window).resize(windowResizeProxy);
|
12130
|
+
if (this.opt('handleWindowResize')) {
|
12131
|
+
$(window).resize(
|
12132
|
+
this.windowResizeProxy = debounce( // prevents rapid calls
|
12133
|
+
this.windowResize.bind(this),
|
12134
|
+
this.opt('windowResizeDelay')
|
12135
|
+
)
|
12136
|
+
);
|
11619
12137
|
}
|
11620
|
-
}
|
12138
|
+
},
|
11621
12139
|
|
11622
12140
|
|
11623
|
-
function
|
12141
|
+
destroy: function() {
|
11624
12142
|
|
11625
|
-
if (
|
11626
|
-
|
12143
|
+
if (this.view) {
|
12144
|
+
this.view.removeElement();
|
11627
12145
|
|
11628
|
-
// NOTE: don't null-out
|
12146
|
+
// NOTE: don't null-out this.view in case API methods are called after destroy.
|
11629
12147
|
// It is still the "current" view, just not rendered.
|
11630
12148
|
}
|
11631
12149
|
|
11632
|
-
toolbarsManager.proxyCall('removeElement');
|
11633
|
-
|
11634
|
-
|
12150
|
+
this.toolbarsManager.proxyCall('removeElement');
|
12151
|
+
this.contentEl.remove();
|
12152
|
+
this.el.removeClass('fc fc-ltr fc-rtl fc-unthemed ui-widget');
|
11635
12153
|
|
11636
|
-
|
12154
|
+
this.el.off('.fc'); // unbind nav link handlers
|
11637
12155
|
|
11638
|
-
if (windowResizeProxy) {
|
11639
|
-
$(window).unbind('resize', windowResizeProxy);
|
12156
|
+
if (this.windowResizeProxy) {
|
12157
|
+
$(window).unbind('resize', this.windowResizeProxy);
|
12158
|
+
this.windowResizeProxy = null;
|
11640
12159
|
}
|
11641
12160
|
|
11642
12161
|
GlobalEmitter.unneeded();
|
11643
|
-
}
|
12162
|
+
},
|
11644
12163
|
|
11645
12164
|
|
11646
|
-
function
|
11647
|
-
return
|
11648
|
-
}
|
12165
|
+
elementVisible: function() {
|
12166
|
+
return this.el.is(':visible');
|
12167
|
+
},
|
11649
12168
|
|
11650
12169
|
|
11651
12170
|
|
@@ -11656,501 +12175,278 @@ function Calendar_constructor(element, overrides) {
|
|
11656
12175
|
// Renders a view because of a date change, view-type change, or for the first time.
|
11657
12176
|
// If not given a viewType, keep the current view but render different dates.
|
11658
12177
|
// Accepts an optional scroll state to restore to.
|
11659
|
-
function
|
11660
|
-
|
12178
|
+
renderView: function(viewType, forcedScroll) {
|
12179
|
+
|
12180
|
+
this.ignoreWindowResize++;
|
11661
12181
|
|
11662
|
-
var needsClearView =
|
12182
|
+
var needsClearView = this.view && viewType && this.view.type !== viewType;
|
11663
12183
|
|
11664
12184
|
// if viewType is changing, remove the old view's rendering
|
11665
12185
|
if (needsClearView) {
|
11666
|
-
freezeContentHeight(); // prevent a scroll jump when view element is removed
|
11667
|
-
clearView();
|
12186
|
+
this.freezeContentHeight(); // prevent a scroll jump when view element is removed
|
12187
|
+
this.clearView();
|
11668
12188
|
}
|
11669
12189
|
|
11670
12190
|
// if viewType changed, or the view was never created, create a fresh view
|
11671
|
-
if (!
|
11672
|
-
|
11673
|
-
viewsByType[viewType] ||
|
11674
|
-
(viewsByType[viewType] =
|
12191
|
+
if (!this.view && viewType) {
|
12192
|
+
this.view =
|
12193
|
+
this.viewsByType[viewType] ||
|
12194
|
+
(this.viewsByType[viewType] = this.instantiateView(viewType));
|
11675
12195
|
|
11676
|
-
|
11677
|
-
$("<div class='fc-view fc-" + viewType + "-view' />").appendTo(
|
12196
|
+
this.view.setElement(
|
12197
|
+
$("<div class='fc-view fc-" + viewType + "-view' />").appendTo(this.contentEl)
|
11678
12198
|
);
|
11679
|
-
toolbarsManager.proxyCall('activateButton', viewType);
|
12199
|
+
this.toolbarsManager.proxyCall('activateButton', viewType);
|
11680
12200
|
}
|
11681
12201
|
|
11682
|
-
if (
|
11683
|
-
|
11684
|
-
if (elementVisible()) {
|
11685
|
-
|
11686
|
-
if (forcedScroll) {
|
11687
|
-
currentView.captureInitialScroll(forcedScroll);
|
11688
|
-
}
|
11689
|
-
|
11690
|
-
currentView.setDate(t.currentDate);
|
12202
|
+
if (this.view) {
|
11691
12203
|
|
11692
|
-
|
11693
|
-
|
11694
|
-
|
12204
|
+
if (forcedScroll) {
|
12205
|
+
this.view.addForcedScroll(forcedScroll);
|
12206
|
+
}
|
11695
12207
|
|
11696
|
-
|
11697
|
-
|
11698
|
-
}
|
12208
|
+
if (this.elementVisible()) {
|
12209
|
+
this.currentDate = this.view.setDate(this.currentDate);
|
11699
12210
|
}
|
11700
12211
|
}
|
11701
12212
|
|
11702
12213
|
if (needsClearView) {
|
11703
|
-
thawContentHeight();
|
12214
|
+
this.thawContentHeight();
|
11704
12215
|
}
|
11705
12216
|
|
11706
|
-
ignoreWindowResize--;
|
11707
|
-
}
|
11708
|
-
t.renderView = renderView;
|
12217
|
+
this.ignoreWindowResize--;
|
12218
|
+
},
|
11709
12219
|
|
11710
12220
|
|
11711
12221
|
// Unrenders the current view and reflects this change in the Header.
|
11712
|
-
// Unregsiters the `
|
11713
|
-
function
|
11714
|
-
toolbarsManager.proxyCall('deactivateButton',
|
11715
|
-
|
11716
|
-
|
11717
|
-
}
|
12222
|
+
// Unregsiters the `view`, but does not remove from viewByType hash.
|
12223
|
+
clearView: function() {
|
12224
|
+
this.toolbarsManager.proxyCall('deactivateButton', this.view.type);
|
12225
|
+
this.view.removeElement();
|
12226
|
+
this.view = null;
|
12227
|
+
},
|
11718
12228
|
|
11719
12229
|
|
11720
12230
|
// Destroys the view, including the view object. Then, re-instantiates it and renders it.
|
11721
12231
|
// Maintains the same scroll state.
|
11722
12232
|
// TODO: maintain any other user-manipulated state.
|
11723
|
-
function
|
11724
|
-
ignoreWindowResize++;
|
11725
|
-
freezeContentHeight();
|
11726
|
-
|
11727
|
-
var viewType = currentView.type;
|
11728
|
-
var scrollState = currentView.queryScroll();
|
11729
|
-
clearView();
|
11730
|
-
calcSize();
|
11731
|
-
renderView(viewType, scrollState);
|
12233
|
+
reinitView: function() {
|
12234
|
+
this.ignoreWindowResize++;
|
12235
|
+
this.freezeContentHeight();
|
11732
12236
|
|
11733
|
-
|
11734
|
-
|
11735
|
-
|
12237
|
+
var viewType = this.view.type;
|
12238
|
+
var scrollState = this.view.queryScroll();
|
12239
|
+
this.clearView();
|
12240
|
+
this.calcSize();
|
12241
|
+
this.renderView(viewType, scrollState);
|
11736
12242
|
|
12243
|
+
this.thawContentHeight();
|
12244
|
+
this.ignoreWindowResize--;
|
12245
|
+
},
|
11737
12246
|
|
11738
12247
|
|
11739
12248
|
// Resizing
|
11740
12249
|
// -----------------------------------------------------------------------------------
|
11741
12250
|
|
11742
12251
|
|
11743
|
-
|
11744
|
-
if (suggestedViewHeight ===
|
11745
|
-
calcSize();
|
12252
|
+
getSuggestedViewHeight: function() {
|
12253
|
+
if (this.suggestedViewHeight === null) {
|
12254
|
+
this.calcSize();
|
11746
12255
|
}
|
11747
|
-
return suggestedViewHeight;
|
11748
|
-
}
|
12256
|
+
return this.suggestedViewHeight;
|
12257
|
+
},
|
11749
12258
|
|
11750
12259
|
|
11751
|
-
|
11752
|
-
return
|
11753
|
-
}
|
12260
|
+
isHeightAuto: function() {
|
12261
|
+
return this.opt('contentHeight') === 'auto' || this.opt('height') === 'auto';
|
12262
|
+
},
|
11754
12263
|
|
11755
12264
|
|
11756
|
-
function
|
11757
|
-
if (elementVisible()) {
|
12265
|
+
updateSize: function(shouldRecalc) {
|
12266
|
+
if (this.elementVisible()) {
|
11758
12267
|
|
11759
12268
|
if (shouldRecalc) {
|
11760
|
-
_calcSize();
|
12269
|
+
this._calcSize();
|
11761
12270
|
}
|
11762
12271
|
|
11763
|
-
ignoreWindowResize++;
|
11764
|
-
|
11765
|
-
ignoreWindowResize--;
|
12272
|
+
this.ignoreWindowResize++;
|
12273
|
+
this.view.updateSize(true); // isResize=true. will poll getSuggestedViewHeight() and isHeightAuto()
|
12274
|
+
this.ignoreWindowResize--;
|
11766
12275
|
|
11767
12276
|
return true; // signal success
|
11768
12277
|
}
|
11769
|
-
}
|
12278
|
+
},
|
11770
12279
|
|
11771
12280
|
|
11772
|
-
function
|
11773
|
-
if (elementVisible()) {
|
11774
|
-
_calcSize();
|
12281
|
+
calcSize: function() {
|
12282
|
+
if (this.elementVisible()) {
|
12283
|
+
this._calcSize();
|
11775
12284
|
}
|
11776
|
-
}
|
12285
|
+
},
|
11777
12286
|
|
11778
12287
|
|
11779
|
-
function
|
11780
|
-
var contentHeightInput =
|
11781
|
-
var heightInput =
|
12288
|
+
_calcSize: function() { // assumes elementVisible
|
12289
|
+
var contentHeightInput = this.opt('contentHeight');
|
12290
|
+
var heightInput = this.opt('height');
|
11782
12291
|
|
11783
12292
|
if (typeof contentHeightInput === 'number') { // exists and not 'auto'
|
11784
|
-
suggestedViewHeight = contentHeightInput;
|
12293
|
+
this.suggestedViewHeight = contentHeightInput;
|
11785
12294
|
}
|
11786
12295
|
else if (typeof contentHeightInput === 'function') { // exists and is a function
|
11787
|
-
suggestedViewHeight = contentHeightInput();
|
12296
|
+
this.suggestedViewHeight = contentHeightInput();
|
11788
12297
|
}
|
11789
12298
|
else if (typeof heightInput === 'number') { // exists and not 'auto'
|
11790
|
-
suggestedViewHeight = heightInput - queryToolbarsHeight();
|
12299
|
+
this.suggestedViewHeight = heightInput - this.queryToolbarsHeight();
|
11791
12300
|
}
|
11792
12301
|
else if (typeof heightInput === 'function') { // exists and is a function
|
11793
|
-
suggestedViewHeight = heightInput() - queryToolbarsHeight();
|
12302
|
+
this.suggestedViewHeight = heightInput() - this.queryToolbarsHeight();
|
11794
12303
|
}
|
11795
12304
|
else if (heightInput === 'parent') { // set to height of parent element
|
11796
|
-
suggestedViewHeight =
|
12305
|
+
this.suggestedViewHeight = this.el.parent().height() - this.queryToolbarsHeight();
|
11797
12306
|
}
|
11798
12307
|
else {
|
11799
|
-
suggestedViewHeight = Math.round(
|
12308
|
+
this.suggestedViewHeight = Math.round(
|
12309
|
+
this.contentEl.width() /
|
12310
|
+
Math.max(this.opt('aspectRatio'), .5)
|
12311
|
+
);
|
11800
12312
|
}
|
11801
|
-
}
|
11802
|
-
|
11803
|
-
|
11804
|
-
function queryToolbarsHeight() {
|
11805
|
-
return toolbarsManager.items.reduce(function(accumulator, toolbar) {
|
11806
|
-
var toolbarHeight = toolbar.el ? toolbar.el.outerHeight(true) : 0; // includes margin
|
11807
|
-
return accumulator + toolbarHeight;
|
11808
|
-
}, 0);
|
11809
|
-
}
|
12313
|
+
},
|
11810
12314
|
|
11811
12315
|
|
11812
|
-
function
|
12316
|
+
windowResize: function(ev) {
|
11813
12317
|
if (
|
11814
|
-
!ignoreWindowResize &&
|
12318
|
+
!this.ignoreWindowResize &&
|
11815
12319
|
ev.target === window && // so we don't process jqui "resize" events that have bubbled up
|
11816
|
-
|
12320
|
+
this.view.renderRange // view has already been rendered
|
11817
12321
|
) {
|
11818
|
-
if (updateSize(true)) {
|
11819
|
-
|
12322
|
+
if (this.updateSize(true)) {
|
12323
|
+
this.view.publiclyTrigger('windowResize', this.el[0]);
|
11820
12324
|
}
|
11821
12325
|
}
|
11822
|
-
}
|
11823
|
-
|
12326
|
+
},
|
11824
12327
|
|
11825
12328
|
|
11826
|
-
/*
|
12329
|
+
/* Height "Freezing"
|
11827
12330
|
-----------------------------------------------------------------------------*/
|
11828
12331
|
|
11829
12332
|
|
11830
|
-
function
|
11831
|
-
|
11832
|
-
|
11833
|
-
|
12333
|
+
freezeContentHeight: function() {
|
12334
|
+
this.contentEl.css({
|
12335
|
+
width: '100%',
|
12336
|
+
height: this.contentEl.height(),
|
12337
|
+
overflow: 'hidden'
|
12338
|
+
});
|
12339
|
+
},
|
12340
|
+
|
12341
|
+
|
12342
|
+
thawContentHeight: function() {
|
12343
|
+
this.contentEl.css({
|
12344
|
+
width: '',
|
12345
|
+
height: '',
|
12346
|
+
overflow: ''
|
12347
|
+
});
|
11834
12348
|
}
|
11835
12349
|
|
12350
|
+
});
|
11836
12351
|
|
12352
|
+
;;
|
11837
12353
|
|
11838
|
-
|
11839
|
-
-----------------------------------------------------------------------------*/
|
12354
|
+
Calendar.mixin({
|
11840
12355
|
|
12356
|
+
header: null,
|
12357
|
+
footer: null,
|
12358
|
+
toolbarsManager: null,
|
11841
12359
|
|
11842
|
-
|
11843
|
-
|
11844
|
-
|
11845
|
-
|
11846
|
-
];
|
11847
|
-
}
|
12360
|
+
|
12361
|
+
initToolbars: function() {
|
12362
|
+
this.header = new Toolbar(this, this.computeHeaderOptions());
|
12363
|
+
this.footer = new Toolbar(this, this.computeFooterOptions());
|
12364
|
+
this.toolbarsManager = new Iterator([ this.header, this.footer ]);
|
12365
|
+
},
|
11848
12366
|
|
11849
12367
|
|
11850
|
-
function
|
12368
|
+
computeHeaderOptions: function() {
|
11851
12369
|
return {
|
11852
12370
|
extraClasses: 'fc-header-toolbar',
|
11853
|
-
layout:
|
12371
|
+
layout: this.opt('header')
|
11854
12372
|
};
|
11855
|
-
}
|
12373
|
+
},
|
11856
12374
|
|
11857
12375
|
|
11858
|
-
function
|
12376
|
+
computeFooterOptions: function() {
|
11859
12377
|
return {
|
11860
12378
|
extraClasses: 'fc-footer-toolbar',
|
11861
|
-
layout:
|
12379
|
+
layout: this.opt('footer')
|
11862
12380
|
};
|
11863
|
-
}
|
12381
|
+
},
|
11864
12382
|
|
11865
12383
|
|
11866
12384
|
// can be called repeatedly and Header will rerender
|
11867
|
-
function
|
11868
|
-
header.
|
12385
|
+
renderHeader: function() {
|
12386
|
+
var header = this.header;
|
12387
|
+
|
12388
|
+
header.setToolbarOptions(this.computeHeaderOptions());
|
11869
12389
|
header.render();
|
12390
|
+
|
11870
12391
|
if (header.el) {
|
11871
|
-
|
12392
|
+
this.el.prepend(header.el);
|
11872
12393
|
}
|
11873
|
-
}
|
12394
|
+
},
|
11874
12395
|
|
11875
12396
|
|
11876
12397
|
// can be called repeatedly and Footer will rerender
|
11877
|
-
function
|
11878
|
-
footer.
|
12398
|
+
renderFooter: function() {
|
12399
|
+
var footer = this.footer;
|
12400
|
+
|
12401
|
+
footer.setToolbarOptions(this.computeFooterOptions());
|
11879
12402
|
footer.render();
|
12403
|
+
|
11880
12404
|
if (footer.el) {
|
11881
|
-
|
12405
|
+
this.el.append(footer.el);
|
11882
12406
|
}
|
11883
|
-
}
|
12407
|
+
},
|
11884
12408
|
|
11885
12409
|
|
11886
|
-
|
11887
|
-
toolbarsManager.proxyCall('updateTitle', title);
|
11888
|
-
}
|
12410
|
+
setToolbarsTitle: function(title) {
|
12411
|
+
this.toolbarsManager.proxyCall('updateTitle', title);
|
12412
|
+
},
|
11889
12413
|
|
11890
12414
|
|
11891
|
-
|
11892
|
-
var now =
|
11893
|
-
var
|
11894
|
-
var
|
11895
|
-
var
|
12415
|
+
updateToolbarButtons: function() {
|
12416
|
+
var now = this.getNow();
|
12417
|
+
var view = this.view;
|
12418
|
+
var todayInfo = view.buildDateProfile(now);
|
12419
|
+
var prevInfo = view.buildPrevDateProfile(this.currentDate);
|
12420
|
+
var nextInfo = view.buildNextDateProfile(this.currentDate);
|
11896
12421
|
|
11897
|
-
toolbarsManager.proxyCall(
|
11898
|
-
(todayInfo.isValid && !isDateWithinRange(now,
|
12422
|
+
this.toolbarsManager.proxyCall(
|
12423
|
+
(todayInfo.isValid && !isDateWithinRange(now, view.currentRange)) ?
|
11899
12424
|
'enableButton' :
|
11900
12425
|
'disableButton',
|
11901
12426
|
'today'
|
11902
12427
|
);
|
11903
12428
|
|
11904
|
-
toolbarsManager.proxyCall(
|
12429
|
+
this.toolbarsManager.proxyCall(
|
11905
12430
|
prevInfo.isValid ?
|
11906
12431
|
'enableButton' :
|
11907
12432
|
'disableButton',
|
11908
12433
|
'prev'
|
11909
12434
|
);
|
11910
12435
|
|
11911
|
-
toolbarsManager.proxyCall(
|
12436
|
+
this.toolbarsManager.proxyCall(
|
11912
12437
|
nextInfo.isValid ?
|
11913
12438
|
'enableButton' :
|
11914
12439
|
'disableButton',
|
11915
12440
|
'next'
|
11916
12441
|
);
|
11917
|
-
};
|
11918
|
-
|
11919
|
-
|
11920
|
-
|
11921
|
-
/* Selection
|
11922
|
-
-----------------------------------------------------------------------------*/
|
11923
|
-
|
11924
|
-
|
11925
|
-
// this public method receives start/end dates in any format, with any timezone
|
11926
|
-
function select(zonedStartInput, zonedEndInput) {
|
11927
|
-
currentView.select(
|
11928
|
-
t.buildSelectSpan.apply(t, arguments)
|
11929
|
-
);
|
11930
|
-
}
|
11931
|
-
|
11932
|
-
|
11933
|
-
function unselect() { // safe to be called before renderView
|
11934
|
-
if (currentView) {
|
11935
|
-
currentView.unselect();
|
11936
|
-
}
|
11937
|
-
}
|
11938
|
-
|
11939
|
-
|
11940
|
-
// Forces navigation to a view for the given date.
|
11941
|
-
// `viewType` can be a specific view name or a generic one like "week" or "day".
|
11942
|
-
function zoomTo(newDate, viewType) {
|
11943
|
-
var spec;
|
11944
|
-
|
11945
|
-
viewType = viewType || 'day'; // day is default zoom
|
11946
|
-
spec = t.getViewSpec(viewType) || t.getUnitViewSpec(viewType);
|
11947
|
-
|
11948
|
-
t.currentDate = newDate.clone();
|
11949
|
-
renderView(spec ? spec.type : null);
|
11950
|
-
}
|
11951
|
-
|
11952
|
-
|
11953
|
-
|
11954
|
-
/* Height "Freezing"
|
11955
|
-
-----------------------------------------------------------------------------*/
|
11956
|
-
|
11957
|
-
|
11958
|
-
t.freezeContentHeight = freezeContentHeight;
|
11959
|
-
t.thawContentHeight = thawContentHeight;
|
11960
|
-
|
11961
|
-
var freezeContentHeightDepth = 0;
|
11962
|
-
|
11963
|
-
|
11964
|
-
function freezeContentHeight() {
|
11965
|
-
if (!(freezeContentHeightDepth++)) {
|
11966
|
-
content.css({
|
11967
|
-
width: '100%',
|
11968
|
-
height: content.height(),
|
11969
|
-
overflow: 'hidden'
|
11970
|
-
});
|
11971
|
-
}
|
11972
|
-
}
|
11973
|
-
|
11974
|
-
|
11975
|
-
function thawContentHeight() {
|
11976
|
-
if (!(--freezeContentHeightDepth)) {
|
11977
|
-
content.css({
|
11978
|
-
width: '',
|
11979
|
-
height: '',
|
11980
|
-
overflow: ''
|
11981
|
-
});
|
11982
|
-
}
|
11983
|
-
}
|
11984
|
-
|
11985
|
-
|
11986
|
-
|
11987
|
-
/* Misc
|
11988
|
-
-----------------------------------------------------------------------------*/
|
11989
|
-
|
11990
|
-
|
11991
|
-
function getCalendar() {
|
11992
|
-
return t;
|
11993
|
-
}
|
11994
|
-
|
11995
|
-
|
11996
|
-
function getView() {
|
11997
|
-
return currentView;
|
11998
|
-
}
|
11999
|
-
|
12000
|
-
|
12001
|
-
function option(name, value) {
|
12002
|
-
var newOptionHash;
|
12003
|
-
|
12004
|
-
if (typeof name === 'string') {
|
12005
|
-
if (value === undefined) { // getter
|
12006
|
-
return t.options[name];
|
12007
|
-
}
|
12008
|
-
else { // setter for individual option
|
12009
|
-
newOptionHash = {};
|
12010
|
-
newOptionHash[name] = value;
|
12011
|
-
setOptions(newOptionHash);
|
12012
|
-
}
|
12013
|
-
}
|
12014
|
-
else if (typeof name === 'object') { // compound setter with object input
|
12015
|
-
setOptions(name);
|
12016
|
-
}
|
12017
|
-
}
|
12018
|
-
|
12019
|
-
|
12020
|
-
function setOptions(newOptionHash) {
|
12021
|
-
var optionCnt = 0;
|
12022
|
-
var optionName;
|
12023
|
-
|
12024
|
-
recordOptionOverrides(newOptionHash);
|
12025
|
-
|
12026
|
-
for (optionName in newOptionHash) {
|
12027
|
-
optionCnt++;
|
12028
|
-
}
|
12029
|
-
|
12030
|
-
// special-case handling of single option change.
|
12031
|
-
// if only one option change, `optionName` will be its name.
|
12032
|
-
if (optionCnt === 1) {
|
12033
|
-
if (optionName === 'height' || optionName === 'contentHeight' || optionName === 'aspectRatio') {
|
12034
|
-
updateSize(true); // true = allow recalculation of height
|
12035
|
-
return;
|
12036
|
-
}
|
12037
|
-
else if (optionName === 'defaultDate') {
|
12038
|
-
return; // can't change date this way. use gotoDate instead
|
12039
|
-
}
|
12040
|
-
else if (optionName === 'businessHours') {
|
12041
|
-
if (currentView) {
|
12042
|
-
currentView.unrenderBusinessHours();
|
12043
|
-
currentView.renderBusinessHours();
|
12044
|
-
}
|
12045
|
-
return;
|
12046
|
-
}
|
12047
|
-
else if (optionName === 'timezone') {
|
12048
|
-
t.rezoneArrayEventSources();
|
12049
|
-
t.refetchEvents();
|
12050
|
-
return;
|
12051
|
-
}
|
12052
|
-
}
|
12053
|
-
|
12054
|
-
// catch-all. rerender the header and footer and rebuild/rerender the current view
|
12055
|
-
renderHeader();
|
12056
|
-
renderFooter();
|
12057
|
-
viewsByType = {}; // even non-current views will be affected by this option change. do before rerender
|
12058
|
-
reinitView();
|
12059
|
-
}
|
12060
|
-
|
12061
|
-
|
12062
|
-
// stores the new options internally, but does not rerender anything.
|
12063
|
-
function recordOptionOverrides(newOptionHash) {
|
12064
|
-
var optionName;
|
12065
|
-
|
12066
|
-
for (optionName in newOptionHash) {
|
12067
|
-
t.dynamicOverrides[optionName] = newOptionHash[optionName];
|
12068
|
-
}
|
12069
|
-
|
12070
|
-
t.viewSpecCache = {}; // the dynamic override invalidates the options in this cache, so just clear it
|
12071
|
-
t.populateOptionsHash(); // this.options needs to be recomputed after the dynamic override
|
12072
|
-
|
12073
|
-
// trigger handlers after this.options has been updated
|
12074
|
-
for (optionName in newOptionHash) {
|
12075
|
-
t.triggerOptionHandlers(optionName); // recall bindOption/bindOptions
|
12076
|
-
}
|
12077
|
-
}
|
12078
|
-
|
12079
|
-
|
12080
|
-
function publiclyTrigger(name, thisObj) {
|
12081
|
-
var args = Array.prototype.slice.call(arguments, 2);
|
12082
|
-
|
12083
|
-
thisObj = thisObj || _element;
|
12084
|
-
this.triggerWith(name, thisObj, args); // Emitter's method
|
12085
|
-
|
12086
|
-
if (t.options[name]) {
|
12087
|
-
return t.options[name].apply(thisObj, args);
|
12088
|
-
}
|
12089
|
-
}
|
12090
|
-
|
12091
|
-
t.initialize();
|
12092
|
-
}
|
12093
|
-
|
12094
|
-
;;
|
12095
|
-
/*
|
12096
|
-
Options binding/triggering system.
|
12097
|
-
*/
|
12098
|
-
Calendar.mixin({
|
12099
|
-
|
12100
|
-
// A map of option names to arrays of handler objects. Initialized to {} in Calendar.
|
12101
|
-
// Format for a handler object:
|
12102
|
-
// {
|
12103
|
-
// func // callback function to be called upon change
|
12104
|
-
// names // option names whose values should be given to func
|
12105
|
-
// }
|
12106
|
-
optionHandlers: null,
|
12107
|
-
|
12108
|
-
// Calls handlerFunc immediately, and when the given option has changed.
|
12109
|
-
// handlerFunc will be given the option value.
|
12110
|
-
bindOption: function(optionName, handlerFunc) {
|
12111
|
-
this.bindOptions([ optionName ], handlerFunc);
|
12112
|
-
},
|
12113
|
-
|
12114
|
-
// Calls handlerFunc immediately, and when any of the given options change.
|
12115
|
-
// handlerFunc will be given each option value as ordered function arguments.
|
12116
|
-
bindOptions: function(optionNames, handlerFunc) {
|
12117
|
-
var handlerObj = { func: handlerFunc, names: optionNames };
|
12118
|
-
var i;
|
12119
|
-
|
12120
|
-
for (i = 0; i < optionNames.length; i++) {
|
12121
|
-
this.registerOptionHandlerObj(optionNames[i], handlerObj);
|
12122
|
-
}
|
12123
|
-
|
12124
|
-
this.triggerOptionHandlerObj(handlerObj);
|
12125
|
-
},
|
12126
|
-
|
12127
|
-
// Puts the given handler object into the internal hash
|
12128
|
-
registerOptionHandlerObj: function(optionName, handlerObj) {
|
12129
|
-
(this.optionHandlers[optionName] || (this.optionHandlers[optionName] = []))
|
12130
|
-
.push(handlerObj);
|
12131
|
-
},
|
12132
|
-
|
12133
|
-
// Reports that the given option has changed, and calls all appropriate handlers.
|
12134
|
-
triggerOptionHandlers: function(optionName) {
|
12135
|
-
var handlerObjs = this.optionHandlers[optionName] || [];
|
12136
|
-
var i;
|
12137
|
-
|
12138
|
-
for (i = 0; i < handlerObjs.length; i++) {
|
12139
|
-
this.triggerOptionHandlerObj(handlerObjs[i]);
|
12140
|
-
}
|
12141
12442
|
},
|
12142
12443
|
|
12143
|
-
// Calls the callback for a specific handler object, passing in the appropriate arguments.
|
12144
|
-
triggerOptionHandlerObj: function(handlerObj) {
|
12145
|
-
var optionNames = handlerObj.names;
|
12146
|
-
var optionValues = [];
|
12147
|
-
var i;
|
12148
|
-
|
12149
|
-
for (i = 0; i < optionNames.length; i++) {
|
12150
|
-
optionValues.push(this.options[optionNames[i]]);
|
12151
|
-
}
|
12152
12444
|
|
12153
|
-
|
12445
|
+
queryToolbarsHeight: function() {
|
12446
|
+
return this.toolbarsManager.items.reduce(function(accumulator, toolbar) {
|
12447
|
+
var toolbarHeight = toolbar.el ? toolbar.el.outerHeight(true) : 0; // includes margin
|
12448
|
+
return accumulator + toolbarHeight;
|
12449
|
+
}, 0);
|
12154
12450
|
}
|
12155
12451
|
|
12156
12452
|
});
|
@@ -12463,6 +12759,7 @@ var instanceComputableOptions = {
|
|
12463
12759
|
|
12464
12760
|
};
|
12465
12761
|
|
12762
|
+
// TODO: make these computable properties in optionsModel
|
12466
12763
|
function populateInstanceComputableOptions(options) {
|
12467
12764
|
$.each(instanceComputableOptions, function(name, func) {
|
12468
12765
|
if (options[name] == null) {
|
@@ -12533,7 +12830,7 @@ function EventManager() { // assumed to be a calendar
|
|
12533
12830
|
|
12534
12831
|
|
12535
12832
|
$.each(
|
12536
|
-
(t.
|
12833
|
+
(t.opt('events') ? [ t.opt('events') ] : []).concat(t.opt('eventSources') || []),
|
12537
12834
|
function(i, sourceInput) {
|
12538
12835
|
var source = buildEventSource(sourceInput);
|
12539
12836
|
if (source) {
|
@@ -12545,7 +12842,7 @@ function EventManager() { // assumed to be a calendar
|
|
12545
12842
|
|
12546
12843
|
|
12547
12844
|
function requestEvents(start, end) {
|
12548
|
-
if (!t.
|
12845
|
+
if (!t.opt('lazyFetching') || isFetchNeeded(start, end)) {
|
12549
12846
|
return fetchEvents(start, end);
|
12550
12847
|
}
|
12551
12848
|
else {
|
@@ -12584,11 +12881,6 @@ function EventManager() { // assumed to be a calendar
|
|
12584
12881
|
};
|
12585
12882
|
|
12586
12883
|
|
12587
|
-
t.getPrunedEventCache = function() {
|
12588
|
-
return prunedCache;
|
12589
|
-
};
|
12590
|
-
|
12591
|
-
|
12592
12884
|
|
12593
12885
|
/* Fetching
|
12594
12886
|
-----------------------------------------------------------------------------*/
|
@@ -12650,7 +12942,7 @@ function EventManager() { // assumed to be a calendar
|
|
12650
12942
|
}
|
12651
12943
|
|
12652
12944
|
if (pendingSourceCnt) {
|
12653
|
-
return
|
12945
|
+
return Promise.construct(function(resolve) {
|
12654
12946
|
t.one('eventsReceived', resolve); // will send prunedCache
|
12655
12947
|
});
|
12656
12948
|
}
|
@@ -12734,7 +13026,7 @@ function EventManager() { // assumed to be a calendar
|
|
12734
13026
|
source,
|
12735
13027
|
rangeStart.clone(),
|
12736
13028
|
rangeEnd.clone(),
|
12737
|
-
t.
|
13029
|
+
t.opt('timezone'),
|
12738
13030
|
callback
|
12739
13031
|
);
|
12740
13032
|
|
@@ -12757,7 +13049,7 @@ function EventManager() { // assumed to be a calendar
|
|
12757
13049
|
t, // this, the Calendar object
|
12758
13050
|
rangeStart.clone(),
|
12759
13051
|
rangeEnd.clone(),
|
12760
|
-
t.
|
13052
|
+
t.opt('timezone'),
|
12761
13053
|
function(events) {
|
12762
13054
|
callback(events);
|
12763
13055
|
t.popLoading();
|
@@ -12792,9 +13084,9 @@ function EventManager() { // assumed to be a calendar
|
|
12792
13084
|
// and not affect the passed-in object.
|
12793
13085
|
var data = $.extend({}, customData || {});
|
12794
13086
|
|
12795
|
-
var startParam = firstDefined(source.startParam, t.
|
12796
|
-
var endParam = firstDefined(source.endParam, t.
|
12797
|
-
var timezoneParam = firstDefined(source.timezoneParam, t.
|
13087
|
+
var startParam = firstDefined(source.startParam, t.opt('startParam'));
|
13088
|
+
var endParam = firstDefined(source.endParam, t.opt('endParam'));
|
13089
|
+
var timezoneParam = firstDefined(source.timezoneParam, t.opt('timezoneParam'));
|
12798
13090
|
|
12799
13091
|
if (startParam) {
|
12800
13092
|
data[startParam] = rangeStart.format();
|
@@ -12802,8 +13094,8 @@ function EventManager() { // assumed to be a calendar
|
|
12802
13094
|
if (endParam) {
|
12803
13095
|
data[endParam] = rangeEnd.format();
|
12804
13096
|
}
|
12805
|
-
if (t.
|
12806
|
-
data[timezoneParam] = t.
|
13097
|
+
if (t.opt('timezone') && t.opt('timezone') != 'local') {
|
13098
|
+
data[timezoneParam] = t.opt('timezone');
|
12807
13099
|
}
|
12808
13100
|
|
12809
13101
|
t.pushLoading();
|
@@ -13212,12 +13504,13 @@ function EventManager() { // assumed to be a calendar
|
|
13212
13504
|
// Will return `false` when input is invalid.
|
13213
13505
|
// `source` is optional
|
13214
13506
|
function buildEventFromInput(input, source) {
|
13507
|
+
var calendarEventDataTransform = t.opt('eventDataTransform');
|
13215
13508
|
var out = {};
|
13216
13509
|
var start, end;
|
13217
13510
|
var allDay;
|
13218
13511
|
|
13219
|
-
if (
|
13220
|
-
input =
|
13512
|
+
if (calendarEventDataTransform) {
|
13513
|
+
input = calendarEventDataTransform(input);
|
13221
13514
|
}
|
13222
13515
|
if (source && source.eventDataTransform) {
|
13223
13516
|
input = source.eventDataTransform(input);
|
@@ -13283,7 +13576,7 @@ function EventManager() { // assumed to be a calendar
|
|
13283
13576
|
if (allDay === undefined) { // still undefined? fallback to default
|
13284
13577
|
allDay = firstDefined(
|
13285
13578
|
source ? source.allDayDefault : undefined,
|
13286
|
-
t.
|
13579
|
+
t.opt('allDayDefault')
|
13287
13580
|
);
|
13288
13581
|
// still undefined? normalizeEventDates will calculate it
|
13289
13582
|
}
|
@@ -13320,7 +13613,7 @@ function EventManager() { // assumed to be a calendar
|
|
13320
13613
|
}
|
13321
13614
|
|
13322
13615
|
if (!eventProps.end) {
|
13323
|
-
if (t.
|
13616
|
+
if (t.opt('forceEventDuration')) {
|
13324
13617
|
eventProps.end = t.getDefaultEventEnd(eventProps.allDay, eventProps.start);
|
13325
13618
|
}
|
13326
13619
|
else {
|
@@ -13673,21 +13966,22 @@ function backupEventDates(event) {
|
|
13673
13966
|
// Determines if the given event can be relocated to the given span (unzoned start/end with other misc data)
|
13674
13967
|
Calendar.prototype.isEventSpanAllowed = function(span, event) {
|
13675
13968
|
var source = event.source || {};
|
13969
|
+
var eventAllowFunc = this.opt('eventAllow');
|
13676
13970
|
|
13677
13971
|
var constraint = firstDefined(
|
13678
13972
|
event.constraint,
|
13679
13973
|
source.constraint,
|
13680
|
-
this.
|
13974
|
+
this.opt('eventConstraint')
|
13681
13975
|
);
|
13682
13976
|
|
13683
13977
|
var overlap = firstDefined(
|
13684
13978
|
event.overlap,
|
13685
13979
|
source.overlap,
|
13686
|
-
this.
|
13980
|
+
this.opt('eventOverlap')
|
13687
13981
|
);
|
13688
13982
|
|
13689
13983
|
return this.isSpanAllowed(span, constraint, overlap, event) &&
|
13690
|
-
(!
|
13984
|
+
(!eventAllowFunc || eventAllowFunc(span, event) !== false);
|
13691
13985
|
};
|
13692
13986
|
|
13693
13987
|
|
@@ -13716,8 +14010,10 @@ Calendar.prototype.isExternalSpanAllowed = function(eventSpan, eventLocation, ev
|
|
13716
14010
|
|
13717
14011
|
// Determines the given span (unzoned start/end with other misc data) can be selected.
|
13718
14012
|
Calendar.prototype.isSelectionSpanAllowed = function(span) {
|
13719
|
-
|
13720
|
-
|
14013
|
+
var selectAllowFunc = this.opt('selectAllow');
|
14014
|
+
|
14015
|
+
return this.isSpanAllowed(span, this.opt('selectConstraint'), this.opt('selectOverlap')) &&
|
14016
|
+
(!selectAllowFunc || selectAllowFunc(span) !== false);
|
13721
14017
|
};
|
13722
14018
|
|
13723
14019
|
|
@@ -13841,7 +14137,7 @@ var BUSINESS_HOUR_EVENT_DEFAULTS = {
|
|
13841
14137
|
// Return events objects for business hours within the current view.
|
13842
14138
|
// Abuse of our event system :(
|
13843
14139
|
Calendar.prototype.getCurrentBusinessHourEvents = function(wholeDay) {
|
13844
|
-
return this.computeBusinessHourEvents(wholeDay, this.
|
14140
|
+
return this.computeBusinessHourEvents(wholeDay, this.opt('businessHours'));
|
13845
14141
|
};
|
13846
14142
|
|
13847
14143
|
// Given a raw input value from options, return events objects for business hours within the current view.
|
@@ -14138,18 +14434,20 @@ var BasicView = FC.BasicView = View.extend({
|
|
14138
14434
|
------------------------------------------------------------------------------------------------------------------*/
|
14139
14435
|
|
14140
14436
|
|
14141
|
-
|
14437
|
+
computeInitialDateScroll: function() {
|
14142
14438
|
return { top: 0 };
|
14143
14439
|
},
|
14144
14440
|
|
14145
14441
|
|
14146
|
-
|
14442
|
+
queryDateScroll: function() {
|
14147
14443
|
return { top: this.scroller.getScrollTop() };
|
14148
14444
|
},
|
14149
14445
|
|
14150
14446
|
|
14151
|
-
|
14152
|
-
|
14447
|
+
applyDateScroll: function(scroll) {
|
14448
|
+
if (scroll.top !== undefined) {
|
14449
|
+
this.scroller.setScrollTop(scroll.top);
|
14450
|
+
}
|
14153
14451
|
},
|
14154
14452
|
|
14155
14453
|
|
@@ -14666,7 +14964,7 @@ var AgendaView = FC.AgendaView = View.extend({
|
|
14666
14964
|
|
14667
14965
|
|
14668
14966
|
// Computes the initial pre-configured scroll state prior to allowing the user to change it
|
14669
|
-
|
14967
|
+
computeInitialDateScroll: function() {
|
14670
14968
|
var scrollTime = moment.duration(this.opt('scrollTime'));
|
14671
14969
|
var top = this.timeGrid.computeTimeTop(scrollTime);
|
14672
14970
|
|
@@ -14681,13 +14979,15 @@ var AgendaView = FC.AgendaView = View.extend({
|
|
14681
14979
|
},
|
14682
14980
|
|
14683
14981
|
|
14684
|
-
|
14982
|
+
queryDateScroll: function() {
|
14685
14983
|
return { top: this.scroller.getScrollTop() };
|
14686
14984
|
},
|
14687
14985
|
|
14688
14986
|
|
14689
|
-
|
14690
|
-
|
14987
|
+
applyDateScroll: function(scroll) {
|
14988
|
+
if (scroll.top !== undefined) {
|
14989
|
+
this.scroller.setScrollTop(scroll.top);
|
14990
|
+
}
|
14691
14991
|
},
|
14692
14992
|
|
14693
14993
|
|