1 /* 2 * StringMapper.js - ilib string mapper class definition 3 * 4 * Copyright © 2014-2015, 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 var ilib = require("./ilib.js"); 21 var Utils = require("./Utils.js"); 22 23 var Locale = require("./Locale.js"); 24 var IString = require("./IString.js"); 25 26 /** 27 * @class 28 * Create a new string mapper instance. <p> 29 * 30 * The options may contain any of the following properties: 31 * 32 * <ul> 33 * <li><i>locale</i> - locale to use when loading the mapper. Some maps are 34 * locale-dependent, and this locale selects the right one. Default if this is 35 * not specified is the current locale. 36 * 37 * <li><i>name</i> - the name of the map to load 38 * 39 * <li><i>mapFunction</i> - specify an algorithmic mapping function to use if 40 * the mapper does not have an explicit mapping for a character. The idea is 41 * to save disk and memory when algorithmic mapping can be done for some of 42 * the characters, but not others. The exceptions can go into the json file, 43 * and the characters that conform to the rule can be mapped algorithmically. 44 * The map function should take a string containing 1 character as a parameter 45 * and should return a string containing one or more characters. If the 46 * character is outside of the range that can be mapped, it should be returned 47 * unchanged. 48 * 49 * <li><i>onLoad</i> - a callback function to call when this object is fully 50 * loaded. When the onLoad option is given, this object will attempt to 51 * load any missing locale data using the ilib loader callback. 52 * When the constructor is done (even if the data is already preassembled), the 53 * onLoad function is called with the current instance as a parameter, so this 54 * callback can be used with preassembled or dynamic loading or a mix of the two. 55 * 56 * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 57 * asynchronously. If this option is given as "false", then the "onLoad" 58 * callback must be given, as the instance returned from this constructor will 59 * not be usable for a while. 60 * 61 * <li><i>loadParams</i> - an object containing parameters to pass to the 62 * loader callback function when locale data is missing. The parameters are not 63 * interpretted or modified in any way. They are simply passed along. The object 64 * may contain any property/value pairs as long as the calling code is in 65 * agreement with the loader callback function as to what those parameters mean. 66 * </ul> 67 * 68 * 69 * @constructor 70 * @param {Object=} options options to initialize this string mapper 71 */ 72 var StringMapper = function (options) { 73 var sync = true, 74 loadParams = undefined; 75 76 this.locale = new Locale(); 77 this.mapData = {}; 78 this.mapFunction = undefined; 79 80 if (options) { 81 if (typeof(options.locale) !== 'undefined') { 82 this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale; 83 } 84 85 if (typeof(options.name) !== 'undefined') { 86 this.name = options.name; 87 } 88 89 if (typeof(options.mapFunction) === 'function') { 90 this.mapFunction = options.mapFunction; 91 } 92 93 if (typeof(options.sync) !== 'undefined') { 94 sync = (options.sync == true); 95 } 96 97 if (typeof(options.loadParams) !== 'undefined') { 98 loadParams = options.loadParams; 99 } 100 } 101 102 Utils.loadData({ 103 object: "StringMapper", 104 locale: this.locale, 105 name: this.name + ".json", 106 sync: sync, 107 loadParams: loadParams, 108 callback: ilib.bind(this, function (map) { 109 this.mapData = map || {}; 110 if (options && typeof(options.onLoad) === 'function') { 111 options.onLoad(this); 112 } 113 }) 114 }); 115 }; 116 117 StringMapper.prototype = { 118 /** 119 * Return the locale that this mapper was constructed. 120 * @returns 121 */ 122 getLocale: function () { 123 return this.locale; 124 }, 125 126 getName: function () { 127 return this.name; 128 }, 129 130 /** 131 * Map a string using the mapping defined in the constructor. This method 132 * iterates through all characters in the string and maps them one-by-one. 133 * If a particular character has a mapping, the mapping result will be 134 * added to the output. If there is no mapping, but there is a mapFunction 135 * defined, the mapFunction results will be added to the result. Otherwise, 136 * the original character from the input string will be added to the result. 137 * 138 * @param {string|IString|undefined} string 139 * @return {string|IString|undefined} 140 */ 141 map: function (string) { 142 var input; 143 if (!string) { 144 return string; 145 } 146 if (typeof(string) === 'string') { 147 input = new IString(string); 148 } else { 149 input = string.toString(); 150 } 151 var ret = ""; 152 var it = input.charIterator(); 153 var c; 154 155 while (it.hasNext()) { 156 c = it.next(); 157 if (this.mapData && this.mapData[c]) { 158 ret += this.mapData[c]; 159 } else if (this.mapFunction) { 160 ret += this.mapFunction(c); 161 } else { 162 ret += c; 163 } 164 } 165 166 return ret; 167 } 168 }; 169 170 module.exports = StringMapper;