1 /* 2 * ListFmt.js - Represent a list formatter. 3 * 4 * Copyright © 2017-2018, JEDLSoft 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 21 // !data list 22 23 var ilib = require("./ilib.js"); 24 var Utils = require("./Utils.js"); 25 var Locale = require("./Locale.js"); 26 27 28 /** 29 * @class 30 * Create a new list formatter object that formats lists of items according to 31 * the options.<p> 32 * 33 * The options object can contain zero or more of the following parameters: 34 * 35 * <ul> 36 * <li><i>locale</i> locale to use to format this list, or undefined to use the 37 * default locale 38 * 39 * <li><i>length</i> - Specify the length of the format to use. The length is the approximate size of the 40 * formatted string. 41 * 42 * <ul> 43 * <li><i>short</i> 44 * <li><i>medium</i> 45 * <li><i>long</i> 46 * <li><i>full</i> 47 * </ul> 48 * 49 * <li><i>style</i> the name of style to use to format the list, or undefined 50 * to use the default "standard" style. another style option is "units". 51 * 52 * <li><i>onLoad</i> - a callback function to call when the locale data is fully loaded and the address has been 53 * parsed. When the onLoad option is given, the address formatter object 54 * will attempt to load any missing locale data using the ilib loader callback. 55 * When the constructor is done (even if the data is already preassembled), the 56 * onLoad function is called with the current instance as a parameter, so this 57 * callback can be used with preassembled or dynamic loading or a mix of the two. 58 * 59 * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 60 * asynchronously. If this option is given as "false", then the "onLoad" 61 * callback must be given, as the instance returned from this constructor will 62 * not be usable for a while. 63 * 64 * <li><i>loadParams</i> - an object containing parameters to pass to the 65 * loader callback function when locale data is missing. The parameters are not 66 * interpretted or modified in any way. They are simply passed along. The object 67 * may contain any property/value pairs as long as the calling code is in 68 * agreement with the loader callback function as to what those parameters mean. 69 * </ul> 70 * 71 * @constructor 72 * @param {Object} options properties that control how this formatter behaves 73 */ 74 var ListFmt = function(options) { 75 this.locale = new Locale(); 76 this.sync = true; 77 this.style = "standard"; 78 this.length = "short"; 79 this.loadParams = {}; 80 81 if (options) { 82 if (options.locale) { 83 this.locale = options.locale; 84 } 85 86 if (typeof(options.sync) !== 'undefined') { 87 this.sync = !!options.sync; 88 } 89 90 if (options.length) { 91 this.length = options.length; 92 } 93 94 if (options.loadParams) { 95 this.loadParams = options.loadParams; 96 } 97 98 if (options.style) { 99 this.style = options.style; 100 } 101 } 102 103 Utils.loadData({ 104 name: "list.json", 105 object: "ListFmt", 106 locale: this.locale, 107 sync: this.sync, 108 loadParams: this.loadParams, 109 callback: ilib.bind(this, function (fmtdata) { 110 this.fmtdata = fmtdata; 111 112 if (options && typeof(options.onLoad) === 'function') { 113 options.onLoad(this); 114 } 115 }) 116 }); 117 }; 118 119 /** 120 * Format a list of strings as grammatical text that is appropriate 121 * for the locale of this formatter. 122 * 123 * @param {Array.<string>} items an array of strings to format in 124 * order that you would like them to appear 125 * @returns {string} a string containing the list of items that 126 * is grammatically correct for the locale of this formatter 127 */ 128 129 ListFmt.prototype.format = function(items) { 130 if (!items || (!ilib.isArray(items))) { 131 return ""; 132 } 133 134 var itemCount = items.length; 135 var fmtTemplate, formattedList; 136 var startFmt, middleFmt, endFmt; 137 var i; 138 139 fmtTemplate = this.fmtdata[this.style][this.length] || this.fmtdata[this.style]; 140 startFmt = fmtTemplate["start"]; 141 middleFmt = fmtTemplate["middle"]; 142 endFmt = fmtTemplate["end"]; 143 144 if (itemCount === 0) { 145 return ""; 146 } 147 else if (itemCount === 1) { 148 formattedList = items.toString(); 149 150 } else if ( itemCount === 2) { 151 fmtTemplate = fmtTemplate["2"]; 152 formattedList = fmtTemplate.replace("{0}", items[0]).replace("{1}", items[1]); 153 154 } else { 155 for(i = itemCount; i >= 0 ; i--){ 156 if (i == itemCount) { 157 formattedList = endFmt.replace("{0}", items[itemCount-2]).replace("{1}", items[itemCount-1]); 158 i = i-2; 159 } else if (i == 0) { 160 formattedList = startFmt.replace("{0}",items[i]).replace("{1}", formattedList); 161 } 162 else { 163 formattedList = middleFmt.replace("{0}",items[i]).replace("{1}", formattedList); 164 } 165 } 166 } 167 return formattedList; 168 }; 169 170 /** 171 * Return the locale of this formatter. 172 * 173 * @returns {string} the locale of this formatter 174 */ 175 ListFmt.prototype.getLocale = function() { 176 return this.locale.getSpec(); 177 }; 178 179 /** 180 * Return the style of names returned by this formatter 181 * @return {string} the style of names returned by this formatter 182 */ 183 ListFmt.prototype.getStyle = function() { 184 return this.style; 185 }; 186 187 module.exports = ListFmt;