component-search-facet-daterange.js

/**
 * Includes functionality for daterange component
 * @module facetDateRange
 * @param  {jQuery} $ Instance of jQuery
 * @param  {Document} document dom document object
 * @return {Object} list of methods for working with date range component
*/
XA.component.search.facet.daterange = (function ($, document) {
    /**
    * This object stores all public api methods
    * @type {Object.<Methods>}
    * @memberOf module:facetDateRange
    * */
    var api = {}, queryModel, urlHelperModel, initialized = false, toUrlDate, fromUrlDate;
    /**
     * format date
     * @param {String} date date that should be formatted
     * @private
     * @memberof module:facetDateRange
     * @alias module:facetDateRange.toUrlDate
     * @returns {String} date in format 'yymmdd'
     */
    toUrlDate = function (date) {
        return date !== null && date !== "" ? $.datepicker.formatDate('yymmdd', date) : "";
    };
    /**
     * format date from url
     * @private
     * @param {String} dateString date that should be formatted
     * @memberof module:facetDateRange
     * @alias module:facetDateRange.fromUrlDate
     * @returns {Date} date
     */
    fromUrlDate = function (dateString) {
        var y = dateString.substr(0, 4),
            m = dateString.substr(4, 2) - 1,
            d = dateString.substr(6, 2),
            D = new Date(y, m, d);

        if (dateString === "") {
            return;
        }

        if (D.getFullYear() == y && D.getMonth() == m && D.getDate() == d)
            return D;
        else
            throw "Invalid date: " + dateString;
    };
    /**
    * @name module:facetDateRange.FacetDateRangeModel
    * @constructor
    * @augments Backbone.Model
    */
    var FacetDateRangeModel = Backbone.Model.extend(
        /** @lends module:facetDateRange.FacetDateRangeModel.prototype **/
        {
            /**
           * Default model options
           * @default
           */
            defaults: {
                dataProperties: {},
                sig: []
            }
        });
    /**
      * @name module:facetDateRange.FacetDateRangeView
      * @constructor
      * @augments Backbone.View
      */
    var FacetDateRangeView = XA.component.search.baseView.extend(
        /** @lends module:facetDateRange.FacetDateRangeView.prototype **/
        {
            /**
            * Initially sets data to model and watches events on which
            * view should be updated
            * @listens module:facetDateRange.FacetDateRangeView~event:change
            * @listens module:XA.component.search.vent~event:hashChanged
            * @memberof module:facetDateRange.FacetDateRangeView
            */
            initialize: function () {
                this.properties = this.$el.data().properties;
                if (this.model) {
                    this.model.set({ dataProperties: this.properties });
                    this.model.set("sig", this.translateSignatures(this.properties.searchResultsSignature, this.properties.f));
                }
                this.model.on("change", this.render, this);
                
                XA.component.search.vent.on("hashChanged", this.updateComponent.bind(this));
            },
            /**
             * list of events for Backbone View
             * @memberof module:facetDateRange.FacetDateRangeView
             * @alias module:facetDateRange.FacetDateRangeView#events
             */
            events: {
                'change .startDate': 'updateFacet',
                'change .endDate': 'updateFacet',
                'click .bottom-remove-filter, .clear-filter': 'clearFilter'
            },
            /**
             * Renders view. Use jquery ui datepicker
             * @memberof module:facetDateRange.FacetDateRangeView
             * @alias module:facetDateRange.FacetDateRangeView#render
             */
            render: function () {
                var fromDateDefaultOffset = parseInt(this.model.get('dataProperties').fromDateDefaultOffset),
                    toDateDefaultOffset = parseInt(this.model.get('dataProperties').toDateDefaultOffset),
                    fromDateFormat = this.model.get('dataProperties').fromDateDisplayFormat,
                    toDateFormat = this.model.get('dataProperties').toDateDisplayFormat,
                    fromDateMonthsShown = this.model.get('dataProperties').fromDateMonthsShown,
                    toDateMonthsShown = this.model.get('dataProperties').toDateMonthsShown,
                    fromDatePastDays = this.model.get('dataProperties').fromDatePastDays,
                    toDateFutureDays = this.model.get('dataProperties').toDateFutureDays,
                    fromDateVisible = this.model.get('dataProperties').fromDateVisible,
                    toDateVisible = this.model.get('dataProperties').toDateVisible,
                    $fromDate = this.$el.find('.startDate'),
                    $toDate = this.$el.find('.endDate'),
                    hashObj = queryModel.parseHashParameters(window.location.hash),
                    sig = this.model.get('sig'),
                    lang = $("html").attr("lang") ? $("html").attr("lang") : "",
                    dates, i;

                if (toDateFormat) {
                    toDateFormat = toDateFormat.replace(/yy/g, "y");
                }
                if (fromDateFormat) {
                    fromDateFormat = fromDateFormat.replace(/yy/g, "y");
                }

                if (fromDateVisible) {
                    $fromDate.datepicker({
                        dateFormat: fromDateFormat,
                        changeMonth: fromDateMonthsShown,
                        changeYear: fromDateMonthsShown,
                        minDate: fromDatePastDays ? (fromDateDefaultOffset != '' ? -1 * fromDateDefaultOffset : new Date(1900, 1, 1)) : new Date()
                    });
                }

                if (toDateVisible) {
                    $toDate.datepicker({
                        dateFormat: toDateFormat,
                        changeMonth: toDateMonthsShown,
                        changeYear: toDateMonthsShown,
                        maxDate: toDateFutureDays ? (toDateDefaultOffset != '' ? toDateDefaultOffset : new Date(2100, 1, 1)) : new Date()
                    });
                }
                $xa.datepicker.setDefaults($xa.datepicker.regional[lang]);
                for (i = 0; i < sig.length; i++) {
                    if (hashObj.hasOwnProperty(sig[i]) && hashObj[sig[i]] != '') {
                        dates = hashObj[sig[i]].split("|");
                        $fromDate.datepicker("setDate", fromUrlDate(dates[0]));
                        $toDate.datepicker("setDate", fromUrlDate(dates[1]));
                    }
                }
            },
            /**
            * Updates hash by calling ["updateHash"]{@link module:searchQuery.updateHash}
            * @memberof module:facetDateRange.FacetDateRangeView
            * @alias module:facetDateRange.FacetDateRangeView#updateFacet
            */
            updateFacet: function (param) {
                var $facetClose = this.$el.find('.facet-heading > span'),
                    $fromDate = this.$el.find('.startDate'),
                    $toDate = this.$el.find('.endDate'),
                    fromDate = $fromDate.length > 0 ? $fromDate.datepicker("getDate") : null,
                    toDate = $toDate.length > 0 ? $toDate.datepicker("getDate") : null,
                    sig = this.model.get('sig');

                queryModel.updateHash(this.updateSignaturesHash(sig, toUrlDate(fromDate) + "|" + toUrlDate(toDate), {}));
                $facetClose.addClass('has-active-facet');
            },
            /**
            * Clears selected filter in component
            * @param {Object} param
            * @memberof module:facetDateRange.FacetDateRangeView
            * @alias module:facetDateRange.FacetDateRangeView#clearFilter
            */
            clearFilter: function (param) {
                var properties = this.model.get('dataProperties'),
                    $facetClose = this.$el.find('.facet-heading > span'),
                    hash = queryModel.parseHashParameters(window.location.hash),
                    sig = this.model.get('sig'),
                    shouldClear = false,
                    facetData,
                    i;

                $facetClose.removeClass('has-active-facet');

                for (i = 0; i < sig.length; i++) {  
                    facetData = sig[i];
                    if (typeof hash[facetData] !== "undefined" && hash[facetData] !== "") {                                      
                        delete properties[facetData];
                        shouldClear = true;
                    }
                }

                if (!shouldClear) {
                    return;
                }

                queryModel.updateHash(this.updateSignaturesHash(sig, "", hash));

                this.model.set({ dataProperties: properties });

                this.$el.find('.startDate').val("");
                this.$el.find('.endDate').val("");
            },
            /**
            * Updates component after changes in hash
            * @param {Object} hash object that stores hash values
            * @memberof module:facetDateRange.FacetDateRangeView
            * @alias module:facetDateRange.FacetDateRangeView#updateComponent
            */
            updateComponent: function (hash) {
                var $fromDate = this.$el.find('.startDate'),
                    $toDate = this.$el.find('.endDate'),
                    sig = this.model.get('sig'),
                    facetPart,
                    dates,
                    i;

                for (i = 0; i < sig.length; i++) {
                    facetPart = sig[i].toLowerCase();
                    if (hash.hasOwnProperty(facetPart) && hash[facetPart] !== '') {
                        dates = hash[facetPart].split("|");
                        if (dates[0] !== "") {
                            this.handleDate($fromDate, dates[0]);
                        }
                        if (dates[1] !== "") {
                            this.handleDate($toDate, dates[1]);
                        }
                    } else {
                        this.clearFilter();
                    }
                }
            },
            /**
            * Updates datepicker date
            * @param {jQuery<DomElement>} control element where start date specified
            * @param {String} value date that should be set  
            * @memberof module:facetDateRange.FacetDateRangeView
            * @alias module:facetDateRange.FacetDateRangeView#handleDate
            */
            handleDate: function (control, value) {
                var $facetClose = this.$el.find('.facet-heading > span');
                if (control.length !== 0 && toUrlDate(control.datepicker('getDate')) !== value) {
                    control.datepicker("setDate", fromUrlDate(value));
                    $facetClose.addClass('has-active-facet');
                } else if (value === "") {
                    control.datepicker('setDate', null);
                }
            }
        });

    /**
    * For each search date range on a page creates instance of 
    * ["FacetDateRangeModel"]{@link module:facetDateRange.FacetDateRangeModel} and 
    * ["FacetDateRangeView"]{@link module:facetDateRange.FacetDateRangeView} 
    * @memberOf module:facetDateRange
    * @alias module:facetDateRange.init
    */
    api.init = function () {
        if ($("body").hasClass("on-page-editor") || initialized) {
            return;
        }

        queryModel = XA.component.search.query;
        urlHelperModel = XA.component.search.url;

        var facetDateRangesList = $(".facet-date-range");
        _.each(facetDateRangesList, function (elem) {
            var model = new FacetDateRangeModel(),
                view = new FacetDateRangeView({ el: $(elem), model: model });
            view.render();
        });

        initialzied = true;
    };

    return api;

}(jQuery, document));

XA.register('facetDateRange', XA.component.search.facet.daterange);