1 /*
  2  * ScriptInfo.js - information about scripts
  3  *
  4  * Copyright © 2012-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 // !data scripts
 21 
 22 var ilib = require("../index.js");
 23 var Utils = require("./Utils.js");
 24 
 25 /**
 26  * @class
 27  * Create a new script info instance. This class encodes information about
 28  * scripts, which are sets of characters used in a writing system.<p>
 29  *
 30  * The options object may contain any of the following properties:
 31  *
 32  * <ul>
 33  * <li><i>onLoad</i> - a callback function to call when the script info object is fully
 34  * loaded. When the onLoad option is given, the script info object will attempt to
 35  * load any missing locale data using the ilib loader callback.
 36  * When the constructor is done (even if the data is already preassembled), the
 37  * onLoad function is called with the current instance as a parameter, so this
 38  * callback can be used with preassembled or dynamic loading or a mix of the two.
 39  *
 40  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or
 41  * asynchronously. If this option is given as "false", then the "onLoad"
 42  * callback must be given, as the instance returned from this constructor will
 43  * not be usable for a while.
 44  *
 45  * <li><i>loadParams</i> - an object containing parameters to pass to the
 46  * loader callback function when locale data is missing. The parameters are not
 47  * interpretted or modified in any way. They are simply passed along. The object
 48  * may contain any property/value pairs as long as the calling code is in
 49  * agreement with the loader callback function as to what those parameters mean.
 50  * </ul>
 51  *
 52  *
 53  * @constructor
 54  * @param {string} script The ISO 15924 4-letter identifier for the script
 55  * @param {Object=} options parameters to initialize this instance
 56  */
 57 var ScriptInfo = function(script, options) {
 58     var sync = true,
 59         loadParams = undefined;
 60 
 61     this.script = script;
 62 
 63     if (options) {
 64         if (typeof(options.sync) !== 'undefined') {
 65             sync = !!options.sync;
 66         }
 67 
 68         if (typeof(options.loadParams) !== 'undefined') {
 69             loadParams = options.loadParams;
 70         }
 71     }
 72 
 73     if (!ilib.data.scripts) {
 74         Utils.loadData({
 75             object: "ScriptInfo",
 76             nonlocale: true,
 77             name: "scripts.json",
 78             sync: sync,
 79             loadParams: loadParams,
 80             callback: ilib.bind(this, function (info) {
 81                 if (!info) {
 82                     info = {"Latn":{"nb":215,"nm":"Latin","lid":"Latin","rtl":false,"ime":false,"casing":true}};
 83                 }
 84                 ilib.data.scripts = info;
 85                 this.info = script && ilib.data.scripts[script];
 86                 if (options && typeof(options.onLoad) === 'function') {
 87                     options.onLoad(this);
 88                 }
 89             })
 90         });
 91     } else {
 92         this.info = ilib.data.scripts[script];
 93         if (options && typeof(options.onLoad) === 'function') {
 94             options.onLoad(this);
 95         }
 96     }
 97 };
 98 
 99 /**
100  * @private
101  */
102 ScriptInfo._getScriptsArray = function() {
103     var ret = [],
104         script = undefined,
105         scripts = ilib.data.scripts;
106 
107     for (script in scripts) {
108         if (script && scripts[script]) {
109             ret.push(script);
110         }
111     }
112 
113     return ret;
114 };
115 
116 /**
117  * Return an array of all ISO 15924 4-letter identifier script identifiers that
118  * this copy of ilib knows about.
119  * @static
120  * @param {boolean} sync whether to find the available ids synchronously (true) or asynchronously (false)
121  * @param {Object} loadParams arbitrary object full of properties to pass to the loader
122  * @param {function(Array.<string>)} onLoad callback function to call when the data is finished loading
123  * @return {Array.<string>} an array of all script identifiers that this copy of
124  * ilib knows about
125  */
126 ScriptInfo.getAllScripts = function(sync, loadParams, onLoad) {
127     if (!ilib.data.scripts) {
128         Utils.loadData({
129             object: "ScriptInfo",
130             locale: "-",
131             name: "scripts.json",
132             sync: sync,
133             loadParams: loadParams,
134             callback: ilib.bind(this, function (info) {
135                 ilib.data.scripts = info;
136 
137                 if (typeof(onLoad) === 'function') {
138                     onLoad(ScriptInfo._getScriptsArray());
139                 }
140             })
141         });
142     } else {
143         if (typeof(onLoad) === 'function') {
144             onLoad(ScriptInfo._getScriptsArray());
145         }
146     }
147 
148     return ScriptInfo._getScriptsArray();
149 };
150 
151 ScriptInfo.prototype = {
152     /**
153      * Return the 4-letter ISO 15924 identifier associated
154      * with this script.
155      * @return {string} the 4-letter ISO code for this script
156      */
157     getCode: function () {
158         return this.info && this.script;
159     },
160 
161     /**
162      * Get the ISO 15924 code number associated with this
163      * script.
164      *
165      * @return {number} the ISO 15924 code number
166      */
167     getCodeNumber: function () {
168         return this.info && this.info.nb || 0;
169     },
170 
171     /**
172      * Get the name of this script in English.
173      *
174      * @return {string} the name of this script in English
175      */
176     getName: function () {
177         return this.info && this.info.nm;
178     },
179 
180     /**
181      * Get the long identifier assciated with this script.
182      *
183      * @return {string} the long identifier of this script
184      */
185     getLongCode: function () {
186         return this.info && this.info.lid;
187     },
188 
189     /**
190      * Return the usual direction that text in this script is written
191      * in. Possible return values are "rtl" for right-to-left,
192      * "ltr" for left-to-right, and "ttb" for top-to-bottom.
193      *
194      * @return {string} the usual direction that text in this script is
195      * written in
196      */
197     getScriptDirection: function() {
198         return (this.info && typeof(this.info.rtl) !== 'undefined' && this.info.rtl) ? "rtl" : "ltr";
199     },
200 
201     /**
202      * Return true if this script typically requires an input method engine
203      * to enter its characters.
204      *
205      * @return {boolean} true if this script typically requires an IME
206      */
207     getNeedsIME: function () {
208         return this.info && this.info.ime ? true : false; // converts undefined to false
209     },
210 
211     /**
212      * Return true if this script uses lower- and upper-case characters.
213      *
214      * @return {boolean} true if this script uses letter case
215      */
216     getCasing: function () {
217         return this.info && this.info.casing ? true : false; // converts undefined to false
218     }
219 };
220 
221 module.exports = ScriptInfo;