Home | History | Annotate | Download | only in cr
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // TODO(rginda): Fill out formatTime, add testcases.
      6 
      7 cr.define('cr', function() {
      8 
      9   /**
     10    * Lookup tables used by bytesToSi.
     11    */
     12   var units = ['B', 'k', 'M', 'G', 'T', 'P'];
     13   var scale = [1, 1e3, 1e6, 1e9, 1e12, 1e15];
     14 
     15   /**
     16    * Construct a new Locale object with a set of strings.
     17    *
     18    * The strings object maps symbolic string names to translated strings
     19    * for the locale.  Lists of translated strings are delimited with the caret
     20    * ('^') character.
     21    *
     22    *  LOCALE_DAYS_SHORT: List of abbreviated day names.
     23    *  LOCALE_MONTHS_SHORT: List of abbreviated month names.
     24    *  LOCALE_FMT_SHORT_DATE: A Locale.prototype.formatTime format specifier
     25    *      representing the short date format (e.g. Apr 1, 2011) for the
     26    *      locale.
     27    */
     28   function Locale(strings) {
     29     this.dateStrings_ = {
     30       dayShort: strings.LOCALE_DAYS_SHORT.split('^'),
     31       monthShort: strings.LOCALE_MONTHS_SHORT.split('^'),
     32       shortDateFormat: strings.LOCALE_FMT_DATE_SHORT
     33     };
     34   }
     35 
     36   Locale.prototype = {
     37     /**
     38      * Convert a number of bytes into an appropriate International System of
     39      * Units (SI) representation, using the correct number separators.
     40      *
     41      * The first time this function is called it computes a lookup table which
     42      * is cached for subsequent calls.
     43      *
     44      * @param {number} bytes The number of bytes.
     45      */
     46     bytesToSi: function(bytes) {
     47       function fmt(s, u) {
     48         var rounded = Math.round(bytes / s * 10) / 10;
     49         return rounded.toLocaleString() + u;
     50       }
     51 
     52       // This loop index is used outside the loop if it turns out |bytes|
     53       // requires the largest unit.
     54       var i;
     55 
     56       for (i = 0; i < units.length - 1; i++) {
     57         if (bytes < scale[i + 1])
     58           return fmt(scale[i], units[i]);
     59       }
     60 
     61       return fmt(scale[i], units[i]);
     62     },
     63 
     64     /**
     65      * Format a date as a string using the given format specifier.
     66      *
     67      * This function is similar to strftime() from the C standard library, with
     68      * the GNU extensions for controlling padding.
     69      *
     70      * The following conversion specifiers are defined:
     71      *
     72      *  %% - A literal '%'
     73      *  %a - The localized abbreviated weekday name.
     74      *  %b - The localized abbreviated month name.
     75      *  %d - The day of the month, zero padded (01-31).
     76      *  %Y - The four digit year.
     77      *
     78      * Between  the  '%'  character and the conversion specifier character, an
     79      * optional flag and field width may be specified.
     80      *
     81      *  The following flag characters are permitted:
     82      *    _  (underscore) Pad a numeric result string with spaces.
     83      *    -  (dash) Do not pad a numeric result string.
     84      *    ^  Convert alphabetic characters in result string to upper case.
     85      *
     86      * TODO(rginda): Implement more conversion specifiers.
     87      *
     88      * @param {Date} date The date to be formatted.
     89      * @param {string} spec The format specification.
     90      */
     91     formatDate: function(date, spec) {
     92       var self = this;
     93       var strings = this.dateStrings_;
     94 
     95       // Called back once for each conversion specifier.
     96       function replaceSpecifier(m, flag, width, code) {
     97 
     98         // Left pad utility.
     99         function lpad(value, ch) {
    100           value = String(value);
    101 
    102           while (width && value.length < width) {
    103             value = ch + value;
    104           }
    105 
    106           return value;
    107         }
    108 
    109         // Format a value according to the selected flag and field width.
    110         function fmt(value, defaultWidth) {
    111           if (flag == '-')  // No padding.
    112             return value;
    113 
    114           if (flag == '^')  // Convert to uppercase.
    115             value = String(value).toUpperCase();
    116 
    117           if (typeof width == 'undefined')
    118             width = defaultWidth;
    119 
    120           // If there is no width specifier, there's nothing to pad.
    121           if (!width)
    122             return value;
    123 
    124           if (flag == '_')  // Pad with spaces.
    125             return lpad(value, ' ');
    126 
    127           // Autodetect padding character.
    128           if (typeof value == 'number')
    129             return lpad(value, '0');
    130 
    131           return lpad(value, ' ');
    132         }
    133 
    134         switch (code) {
    135           case '%': return '%';
    136           case 'a': return fmt(strings.dayShort[date.getDay()]);
    137           case 'b': return fmt(strings.monthShort[date.getMonth()]);
    138           case 'd': return fmt(date.getDate(), 2);
    139           case 'Y': return date.getFullYear();
    140           default:
    141             console.log('Unknown format specifier: ' + code);
    142             return m;
    143         }
    144       }
    145 
    146       // Conversion specifiers start with a '%', optionally contain a
    147       // flag and/or field width, followed by a single letter.
    148       // e.g. %a, %-d, %2l.
    149       return spec.replace(/%([\^\-_])?(\d+)?([%a-z])?/gi, replaceSpecifier);
    150     }
    151   };
    152 
    153   /**
    154    * Storage for the current cr.locale.
    155    */
    156   var locale = null;
    157 
    158   return {
    159     Locale: Locale,
    160     get locale() {
    161       return locale;
    162     },
    163     initLocale: function(strings) {
    164       locale = new Locale(strings);
    165     }
    166   };
    167 });
    168