App-SocialCalc-Multiplayer

 view release on metacpan or  search on metacpan

socialcalc/formatnumber2.js  view on Meta::CPAN

SocialCalc.FormatNumber = {};

SocialCalc.FormatNumber.format_definitions = {}; // Parsed formats are stored here globally

// Most constants that are often customized for localization are in the SocialCalc.Constants module.
// If you use this module standalone, provide at least the "FormatNumber" values.
//

// The following values may be customized externally for further localization of the format definitions themselves,
// but that would make them incompatible with other uses and is discouraged.
//

SocialCalc.FormatNumber.separatorchar = ",";
SocialCalc.FormatNumber.decimalchar = ".";
SocialCalc.FormatNumber.daynames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
SocialCalc.FormatNumber.daynames3 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
SocialCalc.FormatNumber.monthnames3 = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
SocialCalc.FormatNumber.monthnames = ["January", "February", "March", "April", "May", "June", "July", "August", "September",
                                      "October", "November", "December"];

SocialCalc.FormatNumber.allowedcolors =
   {BLACK: "#000000", BLUE: "#0000FF", CYAN: "#00FFFF", GREEN: "#00FF00", MAGENTA: "#FF00FF",
    RED: "#FF0000", WHITE: "#FFFFFF", YELLOW: "#FFFF00"};

SocialCalc.FormatNumber.alloweddates =
   {H: "h]", M: "m]", MM: "mm]", S: "s]", SS: "ss]"};

// Other constants

SocialCalc.FormatNumber.commands =
   {copy: 1, color: 2, integer_placeholder: 3, fraction_placeholder: 4, decimal: 5,
    currency: 6, general:7, separator: 8, date: 9, comparison: 10, section: 11, style: 12};

SocialCalc.FormatNumber.datevalues = {julian_offset: 2415019, seconds_in_a_day: 24 * 60 * 60, seconds_in_an_hour: 60 * 60};

/* *******************

 result = SocialCalc.FormatNumber.formatNumberWithFormat = function(rawvalue, format_string, currency_char)

************************* */

SocialCalc.FormatNumber.formatNumberWithFormat = function(rawvalue, format_string, currency_char) {

   var scc = SocialCalc.Constants;
   var scfn = SocialCalc.FormatNumber;

   var op, operandstr, fromend, cval, operandstrlc;
   var startval, estartval;
   var hrs, mins, secs, ehrs, emins, esecs, ampmstr, ymd;
   var minOK, mpos;
   var result="";
   var thisformat;
   var section, gotcomparison, compop, compval, cpos, oppos;
   var sectioninfo;
   var i, decimalscale, scaledvalue, strvalue, strparts, integervalue, fractionvalue;
   var integerdigits2, integerpos, fractionpos, textcolor, textstyle, separatorchar, decimalchar;
   var value; // working copy to change sign, etc.

   rawvalue = rawvalue-0; // make sure a number
   value = rawvalue;
   if (!isFinite(value)) return "NaN";

   var negativevalue = value < 0 ? 1 : 0; // determine sign, etc.
   if (negativevalue) value = -value;
   var zerovalue = value == 0 ? 1 : 0;

   currency_char = currency_char || scc.FormatNumber_DefaultCurrency;

   scfn.parse_format_string(scfn.format_definitions, format_string); // make sure format is parsed
   thisformat = scfn.format_definitions[format_string]; // Get format structure

   if (!thisformat) throw "Format not parsed error!";

   section = thisformat.sectioninfo.length - 1; // get number of sections - 1

   if (thisformat.hascomparison) { // has comparisons - determine which section
      section = 0; // set to which section we will use
      gotcomparison = 0; // this section has no comparison
      for (cpos=0; ;cpos++) { // scan for comparisons
         op = thisformat.operators[cpos];
         operandstr = thisformat.operands[cpos]; // get next operator and operand
         if (!op) { // at end with no match
            if (gotcomparison) { // if comparison but no match
               format_string = "General"; // use default of General
               scfn.parse_format_string(scfn.format_definitions, format_string);
               thisformat = scfn.format_definitions[format_string];
               section = 0;
               }
            break; // if no comparision, matches on this section
            }
         if (op == scfn.commands.section) { // end of section
            if (!gotcomparison) { // no comparison, so it's a match
               break;
               }
            gotcomparison = 0;
            section++; // check out next one
            continue;
            }
         if (op == scfn.commands.comparison) { // found a comparison - do we meet it?
            i=operandstr.indexOf(":");
            compop=operandstr.substring(0,i);
            compval=operandstr.substring(i+1)-0;
            if ((compop == "<" && rawvalue < compval) ||
                (compop == "<=" && rawvalue <= compval) ||
                (compop == "=" && rawvalue == compval) ||
                (compop == "<>" && rawvalue != compval) ||
                (compop == ">=" && rawvalue >= compval) ||
                (compop == ">" && rawvalue > compval)) { // a match
               break;
               }
            gotcomparison = 1;
            }
         }
      }
   else if (section > 0) { // more than one section (separated by ";")
      if (section == 1) { // two sections
         if (negativevalue) {
            negativevalue = 0; // sign will provided by section, not automatically
            section = 1; // use second section for negative values
            }
         else {
            section = 0; // use first for all others
            }
         }
      else if (section == 2) { // three sections
         if (negativevalue) {
            negativevalue = 0; // sign will provided by section, not automatically
            section = 1; // use second section for negative values
            }
         else if (zerovalue) {
            section = 2; // use third section for zero values
            }
         else {
            section = 0; // use first for positive
            }
         }
      }

   sectioninfo = thisformat.sectioninfo[section]; // look at values for our section

   if (sectioninfo.commas > 0) { // scale by thousands
      for (i=0; i<sectioninfo.commas; i++) {
         value /= 1000;
         }
      }
   if (sectioninfo.percent > 0) { // do percent scaling
      for (i=0; i<sectioninfo.percent; i++) {
         value *= 100;
         }
      }

   decimalscale = 1; // cut down to required number of decimal digits
   for (i=0; i<sectioninfo.fractiondigits; i++) {
      decimalscale *= 10;
      }
   scaledvalue = Math.floor(value * decimalscale + 0.5);
   scaledvalue = scaledvalue / decimalscale;

   if (typeof scaledvalue != "number") return "NaN";
   if (!isFinite(scaledvalue)) return "NaN";

   strvalue = scaledvalue+""; // convert to string (Number.toFixed doesn't do all we need)

//   strvalue = value.toFixed(sectioninfo.fractiondigits); // cut down to required number of decimal digits
                                                         // and convert to string

   if (scaledvalue == 0 && (sectioninfo.fractiondigits || sectioninfo.integerdigits)) {
      negativevalue = 0; // no "-0" unless using multiple sections or General
      }

   if (strvalue.indexOf("e")>=0) { // converted to scientific notation
      return rawvalue+""; // Just return plain converted raw value
      }

   strparts=strvalue.match(/^\+{0,1}(\d*)(?:\.(\d*)){0,1}$/); // get integer and fraction parts
   if (!strparts) return "NaN"; // if not a number
   integervalue = strparts[1];
   if (!integervalue || integervalue=="0") integervalue="";
   fractionvalue = strparts[2];
   if (!fractionvalue) fractionvalue = "";

   if (sectioninfo.hasdate) { // there are date placeholders
      if (rawvalue < 0) { // bad date
         return "??-???-??&nbsp;??:??:??";
         }
      startval = (rawvalue-Math.floor(rawvalue)) * scfn.datevalues.seconds_in_a_day; // get date/time parts
      estartval = rawvalue * scfn.datevalues.seconds_in_a_day; // do elapsed time version, too
      hrs = Math.floor(startval / scfn.datevalues.seconds_in_an_hour);
      ehrs = Math.floor(estartval / scfn.datevalues.seconds_in_an_hour);
      startval = startval - hrs * scfn.datevalues.seconds_in_an_hour;
      mins = Math.floor(startval / 60);
      emins = Math.floor(estartval / 60);
      secs = startval - mins * 60;
      decimalscale = 1; // round appropriately depending if there is ss.0
      for (i=0; i<sectioninfo.fractiondigits; i++) {
         decimalscale *= 10;
         }
      secs = Math.floor(secs * decimalscale + 0.5);
      secs = secs / decimalscale;
      esecs = Math.floor(estartval * decimalscale + 0.5);
      esecs = esecs / decimalscale;
      if (secs >= 60) { // handle round up into next second, minute, etc.
         secs = 0;
         mins++; emins++;
         if (mins >= 60) {
            mins = 0;
            hrs++; ehrs++;
            if (hrs >= 24) {
               hrs = 0;
               rawvalue++;
               }
            }
         }
      fractionvalue = (secs-Math.floor(secs))+""; // for "hh:mm:ss.000"
      fractionvalue = fractionvalue.substring(2); // skip "0."

      ymd = SocialCalc.FormatNumber.convert_date_julian_to_gregorian(Math.floor(rawvalue+scfn.datevalues.julian_offset));

      minOK = 0; // says "m" can be minutes if true
      mspos = sectioninfo.sectionstart; // m scan position in ops
      for ( ; ; mspos++) { // scan for "m" and "mm" to see if any minutes fields, and am/pm
         op = thisformat.operators[mspos];
         operandstr = thisformat.operands[mspos]; // get next operator and operand
         if (!op) break; // don't go past end
         if (op==scfn.commands.section) break;
         if (op==scfn.commands.date) {
            if ((operandstr.toLowerCase()=="am/pm" || operandstr.toLowerCase()=="a/p") && !ampmstr) {
               if (hrs >= 12) {
                  hrs -= 12;
                  ampmstr = operandstr.toLowerCase()=="a/p" ? scc.s_FormatNumber_pm1 : scc.s_FormatNumber_pm; // "P" : "PM";
                  }
               else {
                  ampmstr = operandstr.toLowerCase()=="a/p" ? scc.s_FormatNumber_am1 : scc.s_FormatNumber_am; // "A" : "AM";
                  }
               if (operandstr.indexOf(ampmstr)<0)
                  ampmstr = ampmstr.toLowerCase(); // have case match case in format

socialcalc/formatnumber2.js  view on Meta::CPAN

            }
         if (integervalue.length < sectioninfo.integerdigits
             && integerdigits2 <= sectioninfo.integerdigits - integervalue.length) { // field is wider than value
            if (operandstr == "0" || operandstr == "?") { // fill with appropriate characters
               result += operandstr == "0" ? "0" : "&nbsp;";
               if (sectioninfo.thousandssep) { // see if this is a separator position
                  fromend = sectioninfo.integerdigits - integerdigits2;
                  if (fromend > 2 && fromend % 3 == 0) {
                     result += separatorchar;
                     }
                  }
               }
            }
         else { // normal integer digit - add it
            result += integervalue.charAt(integerpos);
            if (sectioninfo.thousandssep) { // see if this is a separator position
               fromend = integervalue.length - integerpos - 1;
               if (fromend > 2 && fromend % 3 == 0) {
                  result += separatorchar;
                  }
               }
            integerpos++;
            }
         }
      else if (op == scfn.commands.fraction_placeholder) { // add fraction part of number
         if (fractionpos >= fractionvalue.length) {
            if (operandstr == "0" || operandstr == "?") {
               result += operandstr == "0" ? "0" : "&nbsp;";
               }
            }
         else {
            result += fractionvalue.charAt(fractionpos);
            }
         fractionpos++;
         }

      else if (op == scfn.commands.decimal) { // decimal point
         if (negativevalue) {
            result += "-";
            negativevalue = 0;
            }
         result += decimalchar;
         }

      else if (op == scfn.commands.currency) { // currency symbol
         if (negativevalue) {
            result += "-";
            negativevalue = 0;
            }
         result += operandstr;
         }

      else if (op == scfn.commands.general) { // insert "General" conversion

         // *** Cut down number of significant digits to avoid floating point artifacts:

         if (value!=0) { // only if non-zero
            var factor = Math.floor(Math.LOG10E * Math.log(value)); // get integer magnitude as a power of 10
            factor = Math.pow(10, 13-factor); // turn into scaling factor
            value = Math.floor(factor * value + 0.5)/factor; // scale positive value, round, undo scaling
            if (!isFinite(value)) return "NaN";
            }
         if (negativevalue) {
            result += "-";
            }
         strvalue = value+""; // convert original value to string
         if (strvalue.indexOf("e")>=0) { // converted to scientific notation
            result += strvalue;
            continue;
            }
         strparts=strvalue.match(/^\+{0,1}(\d*)(?:\.(\d*)){0,1}$/); // get integer and fraction parts
         integervalue = strparts[1];
         if (!integervalue || integervalue=="0") integervalue="";
         fractionvalue = strparts[2];
         if (!fractionvalue) fractionvalue = "";
         integerpos = 0;
         fractionpos = 0;
         if (integervalue.length) {
            for (;integerpos < integervalue.length; integerpos++) {
               result += integervalue.charAt(integerpos);
               if (sectioninfo.thousandssep) { // see if this is a separator position
                  fromend = integervalue.length - integerpos - 1;
                  if (fromend > 2 && fromend % 3 == 0) {
                     result += separatorchar;
                     }
                  }
               }
             }
         else {
            result += "0";
            }
         if (fractionvalue.length) {
            result += decimalchar;
            for (;fractionpos < fractionvalue.length; fractionpos++) {
               result += fractionvalue.charAt(fractionpos);
               }
            }
         }
      else if (op==scfn.commands.date) { // date placeholder
         operandstrlc = operandstr.toLowerCase();
         if (operandstrlc=="y" || operandstrlc=="yy") {
            result += (ymd.year+"").substring(2);
            }
         else if (operandstrlc=="yyyy") {
            result += ymd.year+"";
            }
         else if (operandstrlc=="d") {
            result += ymd.day+"";
            }
         else if (operandstrlc=="dd") {
            cval = 1000 + ymd.day;
            result += (cval+"").substr(2);
            }
         else if (operandstrlc=="ddd") {
            cval = Math.floor(rawvalue+6) % 7;
            result += scc.s_FormatNumber_daynames3[cval];
            }
         else if (operandstrlc=="dddd") {
            cval = Math.floor(rawvalue+6) % 7;
            result += scc.s_FormatNumber_daynames[cval];
            }



( run in 0.606 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )