fullcalendar.io-rails 3.3.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|