2

I'm trying to get my head around the 11,000+ lines of JavaScript code in FullCalendar in order to be able to build new features into it, and so I am trying to understand the various patterns that are being used, especially the beginning here:

FullCalendar v2.4.0:

(function(factory) {
    if (typeof define === 'function' && define.amd) {
        define([ 'jquery', 'moment' ], factory);
    }
    else if (typeof exports === 'object') { // Node/CommonJS
        module.exports = factory(require('jquery'), require('moment'));
    }
    else {
        factory(jQuery, moment);
    }
})(function($, moment) {

;;

var fc = $.fullCalendar = { version: "2.4.0" };
var fcViews = fc.views = {};


$.fn.fullCalendar = function(options) {
    var args = Array.prototype.slice.call(arguments, 1); // for a possible method call
    var res = this; // what this function will return (this jQuery object by default)

    this.each(function(i, _element) { // loop each DOM element involved
        var element = $(_element);
        var calendar = element.data('fullCalendar'); // get the existing calendar object (if any)
        var singleRes; // the returned value of this single method call

        // a method call
        if (typeof options === 'string') {
            if (calendar && $.isFunction(calendar[options])) {
                singleRes = calendar[options].apply(calendar, args);
                if (!i) {
                    res = singleRes; // record the first method call result
                }
                if (options === 'destroy') { // for the destroy method, must remove Calendar object data
                    element.removeData('fullCalendar');
                }
            }
        }
        // a new calendar initialization
        else if (!calendar) { // don't initialize twice
            calendar = new Calendar(element, options);
            element.data('fullCalendar', calendar);
            calendar.render();
        }
    });

    return res;
};
...

In order to understand what each line of this code is for, I'm trying to build a simplified copy of the it here:

http://jsfiddle.net/edwardtanguay/mbs5uafd/2

What do I need to change to this jsfiddle to get it to the point that it is functioning as FullCalendar where <div id='calendar'></div> produces HTML text in the same way that the FullCalendar module does?

I need to get it to this point so that I can begin building on it and thus coming into an understanding of how the FullCalendar module works in detail.

I've added questions regarding specific lines of code which are not clear.

// where exactly is factory being passed in?
(function(factory) {
    // I understand this code to be part of the 
    // JavaScript specification "Asynchronous Module Definition"
    // and seems to be defining jQuery and moment.js as dependencies
    // but they are available anyway so why do they need to be defined as dependencies here?

    // where is the variable "define" coming from?
    if (typeof define === 'function' && define.amd) {
        define([ 'jquery', 'moment' ], factory);
    }
    // where is is the variable "exports" being defined
    else if (typeof exports === 'object') { // Node/CommonJS
        module.exports = factory(require('jquery'), require('moment'));
    }
    else {
        factory(jQuery, moment);
    }
})(function($, moment) {

    // this I understand as simply defining an object "fullCalendar" in the jQuery scope
    // but what does it have to do with the $.fn.fullCalendar below?
    var fc = $.fullCalendar = { version: "2.4.0" };

    $.fn.fullCalendar = function() {
        return 'calendar test works';
    };
});


$(function() {
    $('#calendar').html('jquery works');    
    $('#calendar').fullCalendar();    
});

ANSWER

Here are my notes on this first block of code for anyone trying to figure this out, basically the first block of code is just making sure that jQuery and moment are loaded and is flexible enough to load them in different ways.

(function(factoryWhatever) {
    // ET: this is checking for AMD script such as require.js, is undefined here and skips through
    // ET: it is just making sure that jquery and moment are loaded
    if (typeof define === 'function' && define.amd) {
        define([ 'jquery', 'moment' ], factoryWhatever);
    }

    // ET: this is checking for Node or CommonJS which can make sure that jquery and moment are loaded
    else if (typeof exports === 'object') { // Node/CommonJS
        module.exports = factoryWhatever(require('jquery'), require('moment'));
    }
    else {
        // ET: if neither an AMD script or Node/CommonJS is running, then it will just execute the massively long function below
        // ET: passing in jQuery and moment which will be called "$" and "moment" inside the function
        factoryWhatever(jQuery, moment);
    }
    // ET: this function from line 23 to 11167 is the whole fullCalendar application which runs with
    // ET: the two dependencies jQuery and moment
})(function($, moment) { 
    ...
});

And here is the simplified code that basically shows how the FullCalendar code is structured:

http://jsfiddle.net/edwardtanguay/xw0s38un/2

(function(factory) {
    factory(jQuery, moment);
})(function($, moment) {
    var fc = $.fullCalendar = { version: "2.4.0" };
    $.fn.fullCalendar = function(options) {    
        var res = this;
        res.html('the calendar');
        return res;
    };
});

$(function() {
    $('#calendar').fullCalendar();    
});
Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047

1 Answers1

1

As you already mentioned, define comes from an AMD script like RequireJS! The code checks if an AMD script is loaded and sets the dependencies.

but they are available anyway so why do they need to be defined as dependencies here?

Are they? Maybe. This is why there is such thing as RequireJS. To make sure these libraries are loaded. Please look at the link above for more infos.

exportcomes from (as the comment behind says) NodeJS (see https://nodejs.org/)

$.fn is the alias to the jQuery prototype. (See: What does jQuery.fn mean?)

Community
  • 1
  • 1
Tom
  • 195
  • 9
  • Great, thanks, that got me past the first part and enabled me to create a simplified sample of how this code is structured, in case any else is trying to understand this: http://jsfiddle.net/edwardtanguay/xw0s38un/2 – Edward Tanguay Aug 26 '15 at 12:07