| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- Calendar.mixin({
- el: null,
- contentEl: null,
- suggestedViewHeight: null,
- windowResizeProxy: null,
- ignoreWindowResize: 0,
- render: function() {
- if (!this.contentEl) {
- this.initialRender();
- }
- else if (this.elementVisible()) {
- // mainly for the public API
- this.calcSize();
- this.renderView();
- }
- },
- initialRender: function() {
- var _this = this;
- var el = this.el;
- el.addClass('fc');
- // event delegation for nav links
- el.on('click.fc', 'a[data-goto]', function(ev) {
- var anchorEl = $(this);
- var gotoOptions = anchorEl.data('goto'); // will automatically parse JSON
- var date = _this.moment(gotoOptions.date);
- var viewType = gotoOptions.type;
- // property like "navLinkDayClick". might be a string or a function
- var customAction = _this.view.opt('navLink' + capitaliseFirstLetter(viewType) + 'Click');
- if (typeof customAction === 'function') {
- customAction(date, ev);
- }
- else {
- if (typeof customAction === 'string') {
- viewType = customAction;
- }
- _this.zoomTo(date, viewType);
- }
- });
- // called immediately, and upon option change
- this.optionsModel.watch('settingTheme', [ '?theme' ], function(opts) {
- var themeClass = ThemeRegistry.getThemeClass(opts.theme);
- var theme = new themeClass(_this.optionsModel);
- var widgetClass = theme.getClass('widget');
- _this.theme = theme;
- if (widgetClass) {
- el.addClass(widgetClass);
- }
- }, function() {
- var widgetClass = _this.theme.getClass('widget');
- _this.theme = null;
- if (widgetClass) {
- el.removeClass(widgetClass);
- }
- });
- // called immediately, and upon option change.
- // HACK: locale often affects isRTL, so we explicitly listen to that too.
- this.optionsModel.watch('applyingDirClasses', [ '?isRTL', '?locale' ], function(opts) {
- el.toggleClass('fc-ltr', !opts.isRTL);
- el.toggleClass('fc-rtl', opts.isRTL);
- });
- this.contentEl = $("<div class='fc-view-container'/>").prependTo(el);
- this.initToolbars();
- this.renderHeader();
- this.renderFooter();
- this.renderView(this.opt('defaultView'));
- if (this.opt('handleWindowResize')) {
- $(window).resize(
- this.windowResizeProxy = debounce( // prevents rapid calls
- this.windowResize.bind(this),
- this.opt('windowResizeDelay')
- )
- );
- }
- },
- destroy: function() {
- if (this.view) {
- this.view.removeElement();
- // NOTE: don't null-out this.view in case API methods are called after destroy.
- // It is still the "current" view, just not rendered.
- }
- this.toolbarsManager.proxyCall('removeElement');
- this.contentEl.remove();
- this.el.removeClass('fc fc-ltr fc-rtl');
- // removes theme-related root className
- this.optionsModel.unwatch('settingTheme');
- this.el.off('.fc'); // unbind nav link handlers
- if (this.windowResizeProxy) {
- $(window).unbind('resize', this.windowResizeProxy);
- this.windowResizeProxy = null;
- }
- GlobalEmitter.unneeded();
- },
- elementVisible: function() {
- return this.el.is(':visible');
- },
- // View Rendering
- // -----------------------------------------------------------------------------------
- // Renders a view because of a date change, view-type change, or for the first time.
- // If not given a viewType, keep the current view but render different dates.
- // Accepts an optional scroll state to restore to.
- renderView: function(viewType, forcedScroll) {
- this.ignoreWindowResize++;
- var needsClearView = this.view && viewType && this.view.type !== viewType;
- // if viewType is changing, remove the old view's rendering
- if (needsClearView) {
- this.freezeContentHeight(); // prevent a scroll jump when view element is removed
- this.clearView();
- }
- // if viewType changed, or the view was never created, create a fresh view
- if (!this.view && viewType) {
- this.view =
- this.viewsByType[viewType] ||
- (this.viewsByType[viewType] = this.instantiateView(viewType));
- this.view.setElement(
- $("<div class='fc-view fc-" + viewType + "-view' />").appendTo(this.contentEl)
- );
- this.toolbarsManager.proxyCall('activateButton', viewType);
- }
- if (this.view) {
- if (forcedScroll) {
- this.view.addForcedScroll(forcedScroll);
- }
- if (this.elementVisible()) {
- this.currentDate = this.view.setDate(this.currentDate);
- }
- }
- if (needsClearView) {
- this.thawContentHeight();
- }
- this.ignoreWindowResize--;
- },
- // Unrenders the current view and reflects this change in the Header.
- // Unregsiters the `view`, but does not remove from viewByType hash.
- clearView: function() {
- this.toolbarsManager.proxyCall('deactivateButton', this.view.type);
- this.view.removeElement();
- this.view = null;
- },
- // Destroys the view, including the view object. Then, re-instantiates it and renders it.
- // Maintains the same scroll state.
- // TODO: maintain any other user-manipulated state.
- reinitView: function() {
- this.ignoreWindowResize++;
- this.freezeContentHeight();
- var viewType = this.view.type;
- var scrollState = this.view.queryScroll();
- this.clearView();
- this.calcSize();
- this.renderView(viewType, scrollState);
- this.thawContentHeight();
- this.ignoreWindowResize--;
- },
- // Resizing
- // -----------------------------------------------------------------------------------
- getSuggestedViewHeight: function() {
- if (this.suggestedViewHeight === null) {
- this.calcSize();
- }
- return this.suggestedViewHeight;
- },
- isHeightAuto: function() {
- return this.opt('contentHeight') === 'auto' || this.opt('height') === 'auto';
- },
- updateSize: function(shouldRecalc) {
- if (this.elementVisible()) {
- if (shouldRecalc) {
- this._calcSize();
- }
- this.ignoreWindowResize++;
- this.view.updateSize(true); // isResize=true. will poll getSuggestedViewHeight() and isHeightAuto()
- this.ignoreWindowResize--;
- return true; // signal success
- }
- },
- calcSize: function() {
- if (this.elementVisible()) {
- this._calcSize();
- }
- },
- _calcSize: function() { // assumes elementVisible
- var contentHeightInput = this.opt('contentHeight');
- var heightInput = this.opt('height');
- if (typeof contentHeightInput === 'number') { // exists and not 'auto'
- this.suggestedViewHeight = contentHeightInput;
- }
- else if (typeof contentHeightInput === 'function') { // exists and is a function
- this.suggestedViewHeight = contentHeightInput();
- }
- else if (typeof heightInput === 'number') { // exists and not 'auto'
- this.suggestedViewHeight = heightInput - this.queryToolbarsHeight();
- }
- else if (typeof heightInput === 'function') { // exists and is a function
- this.suggestedViewHeight = heightInput() - this.queryToolbarsHeight();
- }
- else if (heightInput === 'parent') { // set to height of parent element
- this.suggestedViewHeight = this.el.parent().height() - this.queryToolbarsHeight();
- }
- else {
- this.suggestedViewHeight = Math.round(
- this.contentEl.width() /
- Math.max(this.opt('aspectRatio'), .5)
- );
- }
- },
- windowResize: function(ev) {
- if (
- !this.ignoreWindowResize &&
- ev.target === window && // so we don't process jqui "resize" events that have bubbled up
- this.view.renderRange // view has already been rendered
- ) {
- if (this.updateSize(true)) {
- this.view.publiclyTrigger('windowResize', this.el[0]);
- }
- }
- },
- /* Height "Freezing"
- -----------------------------------------------------------------------------*/
- freezeContentHeight: function() {
- this.contentEl.css({
- width: '100%',
- height: this.contentEl.height(),
- overflow: 'hidden'
- });
- },
- thawContentHeight: function() {
- this.contentEl.css({
- width: '',
- height: '',
- overflow: ''
- });
- }
- });
|