1 | /**
|
2 | * Sutton SignWriting Core Module v1.1.0
|
3 | * https://github.com/Slevinski/SignWriting
|
4 | * Copyright (c) 2007-2019, Steve Slevinski
|
5 | * fsw.mjs is released under the MIT License.
|
6 | */
|
7 |
|
8 | /**
|
9 | * Object of regular expressions for FSW strings
|
10 | *
|
11 | * { symbol, coord, sort, box, prefix, spatial, signbox, sign, term }
|
12 | * @alias fsw.re
|
13 | * @type {object}
|
14 | */
|
15 | let re = {
|
16 | 'symbol': 'S[123][0-9a-f]{2}[0-5][0-9a-f]',
|
17 | 'coord': '[0-9]{3}x[0-9]{3}',
|
18 | 'sort': 'A',
|
19 | 'box': '[BLMR]'
|
20 | };
|
21 | re.prefix = `(?:${re.sort}(?:${re.symbol})+)`;
|
22 | re.spatial = `${re.symbol}${re.coord}`;
|
23 | re.signbox = `${re.box}${re.coord}(?:${re.spatial})*`;
|
24 | re.sign = `${re.prefix}?${re.signbox}`;
|
25 | re.term = `${re.prefix}${re.signbox}`;
|
26 |
|
27 | /**
|
28 | * Object of regular expressions for style strings
|
29 | *
|
30 | * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
|
31 | * @alias style.re
|
32 | * @type {object}
|
33 | */
|
34 | let re$1 = {
|
35 | 'colorize': 'C',
|
36 | 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
|
37 | 'colorname': '[a-zA-Z]+',
|
38 | 'padding': 'P[0-9]{2}',
|
39 | 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
|
40 | 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
|
41 | 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
|
42 | 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
|
43 | };
|
44 | re$1.colorbase = `(?:${re$1.colorhex}|${re$1.colorname})`;
|
45 | re$1.color = `_${re$1.colorbase}_`;
|
46 | re$1.colors = `_${re$1.colorbase}(?:,${re$1.colorbase})?_`;
|
47 | re$1.background = `G${re$1.color}`;
|
48 | re$1.detail = `D${re$1.colors}`;
|
49 | re$1.detailsym = `D[0-9]{2}${re$1.colors}`;
|
50 | re$1.classes = `${re$1.classbase}(?: ${re$1.classbase})*`;
|
51 | re$1.full = `-(${re$1.colorize})?(${re$1.padding})?(${re$1.background})?(${re$1.detail})?(${re$1.zoom})?(?:-((?:${re$1.detailsym})*)((?:${re$1.zoomsym})*))?(?:-(${re$1.classes})?!(?:(${re$1.id})!)?)?`;
|
52 |
|
53 | /** The convert module contains functions to convert between Formal SignWriitng in ASCII (FSW) and SignWriting in Unicode (SWU) characters, along with other types of data.
|
54 | * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
|
55 | * @module convert
|
56 | */
|
57 | /**
|
58 | * Function to convert an FSW coordinate string to an array of x,y integers
|
59 | * @function convert.fsw2coord
|
60 | * @param {string} fswCoord - An FSW coordinate string
|
61 | * @returns {number[]} Array of x,y integers
|
62 | * @example
|
63 | * convert.fsw2coord('500x500')
|
64 | *
|
65 | * return [500, 500]
|
66 | */
|
67 |
|
68 |
|
69 | const fsw2coord = fswCoord => fswCoord.split('x').map(num => parseInt(num));
|
70 |
|
71 | const parse = {
|
72 | /**
|
73 | * Function to parse an fsw symbol with optional coordinate and style string
|
74 | * @function fsw.parse.symbol
|
75 | * @param {string} fswSym - an fsw symbol
|
76 | * @returns {object} elements of fsw symbol
|
77 | * @example
|
78 | * fsw.parse.symbol('S10000500x500-C')
|
79 | *
|
80 | * return {
|
81 | * 'symbol': 'S10000',
|
82 | * 'coord': [500, 500],
|
83 | * 'style': '-C'
|
84 | * }
|
85 | */
|
86 | symbol: fswSym => {
|
87 | const regex = `^(${re.symbol})(${re.coord})?(${re$1.full})?`;
|
88 | const symbol = typeof fswSym === 'string' ? fswSym.match(new RegExp(regex)) : undefined;
|
89 | return {
|
90 | 'symbol': symbol ? symbol[1] : undefined,
|
91 | 'coord': symbol && symbol[2] ? fsw2coord(symbol[2]) : undefined,
|
92 | 'style': symbol ? symbol[3] : undefined
|
93 | };
|
94 | },
|
95 |
|
96 | /**
|
97 | * Function to parse an fsw sign with style string
|
98 | * @function fsw.parse.sign
|
99 | * @param {string} fswSign - an fsw sign
|
100 | * @returns {object} elements of fsw sign
|
101 | * @example
|
102 | * fsw.parse.sign('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C')
|
103 | *
|
104 | * return {
|
105 | * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
|
106 | * box: 'M',
|
107 | * max: [525, 535],
|
108 | * spatials: [
|
109 | * {
|
110 | * symbol: 'S2e748',
|
111 | * coord: [483, 510]
|
112 | * },
|
113 | * {
|
114 | * symbol: 'S10011',
|
115 | * coord: [501, 466]
|
116 | * },
|
117 | * {
|
118 | * symbol: 'S2e704',
|
119 | * coord: [510, 500]
|
120 | * },
|
121 | * {
|
122 | * symbol: 'S10019',
|
123 | * coord: [476, 475]
|
124 | * }
|
125 | * ],
|
126 | * style: '-C'
|
127 | * }
|
128 | */
|
129 | sign: fswSign => {
|
130 | const regex = `^(${re.prefix})?(${re.signbox})(${re$1.full})?`;
|
131 | const sign = typeof fswSign === 'string' ? fswSign.match(new RegExp(regex)) : undefined;
|
132 |
|
133 | if (sign) {
|
134 | return {
|
135 | 'sequence': sign[1] ? sign[1].slice(1).match(/.{6}/g) : undefined,
|
136 | 'box': sign[2][0],
|
137 | 'max': fsw2coord(sign[2].slice(1, 8)),
|
138 | 'spatials': sign[2].length < 9 ? undefined : sign[2].slice(8).match(/(.{13})/g).map(m => {
|
139 | return {
|
140 | symbol: m.slice(0, 6),
|
141 | coord: [parseInt(m.slice(6, 9)), parseInt(m.slice(10, 13))]
|
142 | };
|
143 | }),
|
144 | 'style': sign[3]
|
145 | };
|
146 | } else {
|
147 | return {};
|
148 | }
|
149 | }
|
150 | };
|
151 |
|
152 | /**
|
153 | * Array of numbers for kinds of symbols: writing, location, and punctuation.
|
154 | * @alias fsw.kind
|
155 | * @type {array}
|
156 | */
|
157 |
|
158 | const kind = [0x100, 0x37f, 0x387];
|
159 | /**
|
160 | * Array of numbers for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
|
161 | * @alias fsw.category
|
162 | * @type {array}
|
163 | */
|
164 |
|
165 | const category = [0x100, 0x205, 0x2f7, 0x2ff, 0x36d, 0x37f, 0x387];
|
166 | /**
|
167 | * Array of numbers for the 30 symbol groups.
|
168 | * @alias fsw.group
|
169 | * @type {array}
|
170 | */
|
171 |
|
172 | const group = [0x100, 0x10e, 0x11e, 0x144, 0x14c, 0x186, 0x1a4, 0x1ba, 0x1cd, 0x1f5, 0x205, 0x216, 0x22a, 0x255, 0x265, 0x288, 0x2a6, 0x2b7, 0x2d5, 0x2e3, 0x2f7, 0x2ff, 0x30a, 0x32a, 0x33b, 0x359, 0x36d, 0x376, 0x37f, 0x387];
|
173 | /**
|
174 | * Object of symbol ranges with starting and ending numbers.
|
175 | *
|
176 | * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
|
177 | * @alias fsw.ranges
|
178 | * @type {object}
|
179 | */
|
180 |
|
181 | const ranges = {
|
182 | 'all': [0x100, 0x38b],
|
183 | 'writing': [0x100, 0x37e],
|
184 | 'hand': [0x100, 0x204],
|
185 | 'movement': [0x205, 0x2f6],
|
186 | 'dynamic': [0x2f7, 0x2fe],
|
187 | 'head': [0x2ff, 0x36c],
|
188 | 'hcenter': [0x2ff, 0x36c],
|
189 | 'vcenter': [0x2ff, 0x375],
|
190 | 'trunk': [0x36d, 0x375],
|
191 | 'limb': [0x376, 0x37e],
|
192 | 'location': [0x37f, 0x386],
|
193 | 'punctuation': [0x387, 0x38b]
|
194 | };
|
195 | /**
|
196 | * Function to test if symbol is of a certain type.
|
197 | * @function fsw.isType
|
198 | * @param {string} key - an FSW symbol key
|
199 | * @param {string} type - the name of a symbol range
|
200 | * @returns {boolean} is symbol of specified type
|
201 | * @example
|
202 | * fsw.isType('S10000', 'hand')
|
203 | *
|
204 | * return true
|
205 | */
|
206 |
|
207 | const isType = (key, type) => {
|
208 | const parsed = parse.symbol(key);
|
209 |
|
210 | if (parsed.symbol) {
|
211 | const dec = parseInt(parsed.symbol.slice(1, 4), 16);
|
212 | const range = ranges[type];
|
213 |
|
214 | if (range) {
|
215 | return range[0] <= dec && range[1] >= dec;
|
216 | }
|
217 | }
|
218 |
|
219 | return false;
|
220 | };
|
221 |
|
222 | /**
|
223 | * Array of colors associated with the seven symbol categories.
|
224 | * @alias fsw.colors
|
225 | * @type {array}
|
226 | */
|
227 |
|
228 | const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
|
229 | /**
|
230 | * Function that returns the standardized color for a symbol.
|
231 | * @function fsw.colorize
|
232 | * @param {string} key - an FSW symbol key
|
233 | * @returns {string} name of standardized color for symbol
|
234 | * @example
|
235 | * fsw.colorize('S10000')
|
236 | *
|
237 | * return '#0000CC'
|
238 | */
|
239 |
|
240 | const colorize = key => {
|
241 | const parsed = parse.symbol(key);
|
242 | let color = '#000000';
|
243 |
|
244 | if (parsed.symbol) {
|
245 | const dec = parseInt(parsed.symbol.slice(1, 4), 16);
|
246 | const index = category.findIndex(val => val > dec);
|
247 | color = colors[index < 0 ? 6 : index - 1];
|
248 | }
|
249 |
|
250 | return color;
|
251 | };
|
252 |
|
253 | export { category, colorize, colors, group, isType, kind, parse, ranges, re };
|
254 |
|
255 | /* help fund development on https://patreon.com/signwriting */
|