1. #11
    Sencha User interfasys's Avatar
    Join Date
    Mar 2011
    Location
    UK & Switzerland
    Posts
    125
    Vote Rating
    1
    interfasys is on a distinguished road

      0  

    Default


    Here is a version that works with Sencha touch. I've also added a cutoff time after which a normal date will be displayed.

    Code:
    Ext.fc.fuzzyDate = function() {
        var defaultConfig = function() {
            return{
                refreshInterval: 60,
                onErrorWriteTitle: true,
                itemSelector: 'span.fuzzyDate',
                cutoff: 172800,
                defaultReturnFormat: 'd/m/Y, H:i',
                dateFormats: [
                    "Y-m-d H:i:s", //ISO8601Long
                    "Y-m-d", //ISO8601Short
                    "h:i:s", //time
                    "H:i:s", //time
                    "n/j/Y", //ShortDate
                    "l, F d, Y", //LongDate
                    "l, F d, Y g:i:s A", //FullDateTime
                    "F d", //MonthDay
                    "g:i A", //ShortTime
                    "g:i:s A", //LongTime
                    "Y-m-d\\TH:i:s", //SortableDateTime
                    "Y-m-d H:i:sO", //UniversalSortableDateTime
                    "F, Y", //YearMonth
                    "d/m/Y, H:i:s", // Euro format
                    "D, d F Y G:i:s O" // Twitter format
                ],
                translation: {
                    prefixAgo        : '',
                    prefixFromNow    : '',
                    suffixAgo        : "ago",
                    suffixFromNow    : "from now",
    
                    now         : "seconds",
                    seconds     : "less than a minute",
                    minute      : "about a minute",
                    minutes     : "%d minutes",
                    hour        : "about an hour",
                    hours       : "about %d hours",
                    day         : "a day",
                    days        : "about %d days",
                    month       : "about a month",
                    months      : "about %d months",
                    year        : "about a year",
                    years       : "about %d years"
                },
                offsets: {
                    //values are exclusive, they will be evaluated as date < now or date < oneYear
                    now         : 15, //number of seconds a date is considered seconds
                    minute      : 45, //number of seconds a date is considered less than a minute
                    minuteOffset: 90, //number of seconds a date is considered about a minute
                    xminutes    : 50, //number of minutes a date should be represented as x minutes
                    oneHour     : 80, //number of minutes a date should be represented as one hour
                    xHours      : 24, //number of hours a date should be represented as x hours
                    oneDay      : 48, //number of hours a date should be represented as one day
                    xDays       : 30, //number of days a date should be represented as X days
                    oneMonth    : 60, //number of days a date should be represented as one month
                    xMonths     : 365, //number of days a date should be represented as x months
                    oneYear     : 2 //number of years a date should be represented as one year
                }
            }
        };
    
        /**
         * Adds the number of minutes or seconds or days, etc.
         * @param text
         * @param value
         */
        function sprintf(text, value) {
            //I just need %d for one parameter
            return text.replace(/%d/, value);
        }
    
        /**
         * Determines which format to use
         * @param str
         * @param formats
         */
        function parseDate(str, formats) {
            var d = null;
            for (i = 0; i < formats.length; i++) {
                d = Date.parseDate(str, formats[i]);
                if (d) {
                    return d
                }
            }
    
            return false;
        }
    
        /**
         * Returns the relative time
         * @param dateObject
         * @param options
         */
        var dateTimeToString = function (dateObject, options) {
            var t = options.translation,
                    cutoff = options.cutoff,
                    defaultReturnFormat = options.defaultReturnFormat,
                    now = new Date(),
                    offset = now.format('U') - dateObject.format('U');
            //if < 0 then date is in future
    
            if (Math.abs(offset) < cutoff) {
                if (offset < 0) {
                    suffix = t.suffixFromNow;
                    prefix = t.prefixFromNow;
                } else {
                    suffix = t.suffixAgo;
                    prefix = t.prefixAgo;
                }
    
                var seconds = Math.abs(offset);
                var minutes = Math.floor(seconds / 60);
                var hours = Math.floor(minutes / 60);
                var days = Math.floor(hours / 24);
                var years = Math.floor(days / 365);
    
                var fuzzy = false ||
                        seconds < options.offsets.now && sprintf(t.seconds, Math.round(now)) || //seconds
                        seconds < options.offsets.minute && sprintf(t.seconds, Math.round(seconds)) || //about 1 minute
                        seconds < options.offsets.minuteOffset && sprintf(t.minute, 1) || //about x minutes
                        minutes < options.offsets.xminutes && sprintf(t.minutes, Math.round(minutes)) || //about 1 hour
                        minutes < options.offsets.oneHour && sprintf(t.hour, 1) || //about x hours
                        hours < options.offsets.xHours && sprintf(t.hours, Math.round(hours)) || //about 1 day
                        hours < options.offsets.oneDay && sprintf(t.day, 1) || //about x days
                        days < options.offsets.xDays && sprintf(t.days, Math.floor(days)) || //about 1 month
                        days < options.offsets.oneMonth && sprintf(t.month, 1) || //about x months
                        days < options.offsets.xMonths && sprintf(t.months, Math.floor(days / 30)) || //about 1 year
                        years < options.offsets.oneYear && sprintf(t.year, 1) || //about x years
                        sprintf(t.years, Math.floor(years));
    
                return prefix + " " + fuzzy + " " + suffix;
            } else {
                return dateObject.format(defaultReturnFormat);
            }
        };
    
        /**
         * Parses the custom options
         * @param config
         */
        var processOptions = function(config) {
            var o = defaultConfig();
            var options = {};
            Ext.apply(options, config, o);
    
            return options;
        };
    
        //public start
        return{
            options: null,
            items: [],
    
            /**
             * Constructor
             * @param config
             */
            init : function (config) {
                this.options = processOptions(config);
                this.refresh();
            },
    
            /**
             * Returns the translated date
             * @param str
             * @param options
             */
            translate : function(str, options) {
                var d = parseDate(str, options.dateFormats);
                if (d) {
                    return (dateTimeToString(d, options));
                } else {
                    if (options.onErrorWriteTitle) {
                        return (str);
                    }
                }
                return false;
            },
    
            /**
             * Refreshes the relative time of all the Components matching the itemSelector
             */
            refresh: function() {
                Ext.select(this.options.itemSelector).each(function(el, c, idx) {
                    el.update(this.translate(el.dom.title, this.options));
                }, this);
    
                if (this.options.refreshInterval > 0) {
                    Ext.defer(this.refresh, this.options.refreshInterval * 1000, this);
                }
            },
    
            /**
             * Translates the date contained in a specific Component, identified by its id
             * @param domId
             * @param config
             */
            applyTo: function (domId, config) {
                var options = processOptions(config),
                        el = Ext.get(domId);
    
                el.update(this.translate(el.dom.title, options));
    
                if (options.refreshInterval > 0) {
                    Ext.defer(this.applyTo, options.refreshInterval * 1000, this, [domId, config]);
                }
            }
    
        };//public -- end
    };
    Last edited by interfasys; 30 May 2011 at 10:52 AM. Reason: Ext.defer already creates a delegate