abcjs 6.2.3 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +4 -0
  2. package/RELEASE.md +40 -1
  3. package/dist/abcjs-basic-min.js +2 -2
  4. package/dist/abcjs-basic.js +751 -416
  5. package/dist/abcjs-basic.js.map +1 -1
  6. package/dist/abcjs-plugin-min.js +2 -2
  7. package/index.js +2 -0
  8. package/package.json +1 -1
  9. package/plugin.js +1 -1
  10. package/src/api/abc_tablatures.js +48 -13
  11. package/src/parse/abc_parse_directive.js +17 -16
  12. package/src/parse/abc_parse_header.js +22 -19
  13. package/src/parse/abc_tokenizer.js +72 -7
  14. package/src/parse/tune-builder.js +60 -1
  15. package/src/synth/synth-controller.js +6 -2
  16. package/src/tablatures/instruments/string-patterns.js +11 -0
  17. package/src/tablatures/instruments/{guitar/guitar-patterns.js → tab-string-patterns.js} +6 -6
  18. package/src/tablatures/instruments/{violin/tab-violin.js → tab-string.js} +13 -11
  19. package/src/tablatures/tab-absolute-elements.js +16 -7
  20. package/src/tablatures/tab-renderer.js +22 -9
  21. package/src/test/abc_parser_lint.js +13 -12
  22. package/src/write/creation/abstract-engraver.js +3 -2
  23. package/src/write/creation/add-chord.js +102 -82
  24. package/src/write/creation/add-text-if.js +2 -2
  25. package/src/write/creation/decoration.js +14 -8
  26. package/src/write/creation/elements/bottom-text.js +62 -47
  27. package/src/write/creation/elements/rich-text.js +51 -0
  28. package/src/write/creation/elements/top-text.js +37 -11
  29. package/src/write/creation/glyphs.js +1 -1
  30. package/src/write/draw/absolute.js +4 -1
  31. package/src/write/draw/draw.js +13 -4
  32. package/src/write/draw/non-music.js +3 -1
  33. package/src/write/draw/relative.js +1 -1
  34. package/src/write/draw/tempo.js +1 -1
  35. package/src/write/draw/text.js +10 -0
  36. package/src/write/engraver-controller.js +54 -13
  37. package/src/write/helpers/classes.js +1 -1
  38. package/src/write/helpers/get-font-and-attr.js +8 -1
  39. package/src/write/helpers/get-text-size.js +8 -1
  40. package/src/write/svg.js +30 -0
  41. package/temp.txt +50 -0
  42. package/types/index.d.ts +46 -6
  43. package/version.js +1 -1
  44. package/.github/workflows/tests.yml +0 -29
  45. package/src/tablatures/instruments/guitar/tab-guitar.js +0 -48
  46. package/src/tablatures/instruments/violin/violin-patterns.js +0 -23
@@ -69,6 +69,7 @@ var supportsAudio = __webpack_require__(/*! ./src/synth/supports-audio */ "./src
69
69
  var playEvent = __webpack_require__(/*! ./src/synth/play-event */ "./src/synth/play-event.js");
70
70
  var SynthController = __webpack_require__(/*! ./src/synth/synth-controller */ "./src/synth/synth-controller.js");
71
71
  var getMidiFile = __webpack_require__(/*! ./src/synth/get-midi-file */ "./src/synth/get-midi-file.js");
72
+ var midiRenderer = __webpack_require__(/*! ./src/synth/abc_midi_renderer */ "./src/synth/abc_midi_renderer.js");
72
73
  abcjs.synth = {
73
74
  CreateSynth: CreateSynth,
74
75
  instrumentIndexToName: instrumentIndexToName,
@@ -81,7 +82,8 @@ abcjs.synth = {
81
82
  supportsAudio: supportsAudio,
82
83
  playEvent: playEvent,
83
84
  getMidiFile: getMidiFile,
84
- sequence: sequence
85
+ sequence: sequence,
86
+ midiRenderer: midiRenderer
85
87
  };
86
88
  abcjs['Editor'] = __webpack_require__(/*! ./src/edit/abc_editor */ "./src/edit/abc_editor.js");
87
89
  abcjs['EditArea'] = __webpack_require__(/*! ./src/edit/abc_editarea */ "./src/edit/abc_editarea.js");
@@ -203,17 +205,42 @@ module.exports = animation;
203
205
  * where plugin represents a plugin instance
204
206
  *
205
207
  */
206
- var ViolinTablature = __webpack_require__(/*! ../tablatures/instruments/violin/tab-violin */ "./src/tablatures/instruments/violin/tab-violin.js");
207
- var GuitarTablature = __webpack_require__(/*! ../tablatures/instruments/guitar/tab-guitar */ "./src/tablatures/instruments/guitar/tab-guitar.js");
208
+ var StringTablature = __webpack_require__(/*! ../tablatures/instruments/tab-string */ "./src/tablatures/instruments/tab-string.js");
208
209
 
209
210
  /* extend the table below when adding a new instrument plugin */
210
211
 
211
212
  // Existing tab classes
212
213
  var pluginTab = {
213
- 'violin': 'ViolinTab',
214
- 'fiddle': 'ViolinTab',
215
- 'mandolin': 'ViolinTab',
216
- 'guitar': 'GuitarTab'
214
+ 'violin': {
215
+ name: 'StringTab',
216
+ defaultTuning: ['G,', 'D', 'A', 'e'],
217
+ isTabBig: false,
218
+ tabSymbolOffset: 0
219
+ },
220
+ 'fiddle': {
221
+ name: 'StringTab',
222
+ defaultTuning: ['G,', 'D', 'A', 'e'],
223
+ isTabBig: false,
224
+ tabSymbolOffset: 0
225
+ },
226
+ 'mandolin': {
227
+ name: 'StringTab',
228
+ defaultTuning: ['G,', 'D', 'A', 'e'],
229
+ isTabBig: false,
230
+ tabSymbolOffset: 0
231
+ },
232
+ 'guitar': {
233
+ name: 'StringTab',
234
+ defaultTuning: ['E,', 'A,', 'D', 'G', 'B', 'e'],
235
+ isTabBig: true,
236
+ tabSymbolOffset: 0
237
+ },
238
+ 'fiveString': {
239
+ name: 'StringTab',
240
+ defaultTuning: ['C,', 'G,', 'D', 'A', 'e'],
241
+ isTabBig: false,
242
+ tabSymbolOffset: -.95
243
+ }
217
244
  };
218
245
  var abcTablatures = {
219
246
  inited: false,
@@ -258,7 +285,7 @@ var abcTablatures = {
258
285
  var tabName = pluginTab[instrument];
259
286
  var plugin = null;
260
287
  if (tabName) {
261
- plugin = this.plugins[tabName];
288
+ plugin = this.plugins[tabName.name];
262
289
  }
263
290
  if (plugin) {
264
291
  if (params.visualTranspose != 0) {
@@ -270,7 +297,8 @@ var abcTablatures = {
270
297
  classz: plugin,
271
298
  tuneNumber: tuneNumber,
272
299
  params: args,
273
- instance: null
300
+ instance: null,
301
+ tabType: tabName
274
302
  };
275
303
  // proceed with tab plugin init
276
304
  // plugin.init(tune, tuneNumber, args, ii);
@@ -296,20 +324,50 @@ var abcTablatures = {
296
324
  */
297
325
  layoutTablatures: function layoutTablatures(renderer, abcTune) {
298
326
  var tabs = abcTune.tablatures;
327
+
299
328
  // chack tabs request for each staffs
329
+ var staffLineCount = 0;
330
+
331
+ // Clear the suppression flag
332
+ if (tabs && tabs.length > 0) {
333
+ var nTabs = tabs.length;
334
+ for (var kk = 0; kk < nTabs; ++kk) {
335
+ if (tabs[kk] && tabs[kk].params.firstStaffOnly) {
336
+ tabs[kk].params.suppress = false;
337
+ }
338
+ }
339
+ }
300
340
  for (var ii = 0; ii < abcTune.lines.length; ii++) {
301
341
  var line = abcTune.lines[ii];
342
+ if (line.staff) {
343
+ staffLineCount++;
344
+ }
345
+
346
+ // MAE 27Nov2023
347
+ // If tab param "firstStaffOnly", remove the tab label after the first staff
348
+ if (staffLineCount > 1) {
349
+ if (tabs && tabs.length > 0) {
350
+ var nTabs = tabs.length;
351
+ for (var kk = 0; kk < nTabs; ++kk) {
352
+ if (tabs[kk].params.firstStaffOnly) {
353
+ // Set the staff draw suppression flag
354
+ tabs[kk].params.suppress = true;
355
+ }
356
+ }
357
+ }
358
+ }
302
359
  var curStaff = line.staff;
303
360
  if (curStaff) {
361
+ var maxStaves = curStaff.length;
304
362
  for (var jj = 0; jj < curStaff.length; jj++) {
305
- if (tabs[jj]) {
363
+ if (tabs[jj] && jj < maxStaves) {
306
364
  // tablature requested for staff
307
365
  var tabPlugin = tabs[jj];
308
366
  if (tabPlugin.instance == null) {
309
367
  tabPlugin.instance = new tabPlugin.classz();
310
368
  // plugin.init(tune, tuneNumber, args, ii);
311
369
  // call initer first
312
- tabPlugin.instance.init(abcTune, tabPlugin.tuneNumber, tabPlugin.params, jj);
370
+ tabPlugin.instance.init(abcTune, tabPlugin.tuneNumber, tabPlugin.params, jj, tabPlugin.tabType);
313
371
  }
314
372
  // render next
315
373
  tabPlugin.instance.render(renderer, line, jj);
@@ -324,8 +382,7 @@ var abcTablatures = {
324
382
  init: function init() {
325
383
  // just register plugin hosted by abcjs
326
384
  if (!this.inited) {
327
- this.register(new ViolinTablature());
328
- this.register(new GuitarTablature());
385
+ this.register(new StringTablature());
329
386
  this.inited = true;
330
387
  }
331
388
  }
@@ -4169,31 +4226,30 @@ var parseDirective = {};
4169
4226
  }
4170
4227
  };
4171
4228
  parseDirective.parseFontChangeLine = function (textstr) {
4229
+ // We don't want to match two dollar signs, so change those temporarily
4230
+ textstr = textstr.replace(/\$\$/g, "\x03");
4172
4231
  var textParts = textstr.split('$');
4173
4232
  if (textParts.length > 1 && multilineVars.setfont) {
4174
- var textarr = [{
4175
- text: textParts[0]
4176
- }];
4233
+ var textarr = [];
4234
+ if (textParts[0] !== '')
4235
+ // did the original string start with `$`?
4236
+ textarr.push({
4237
+ text: textParts[0]
4238
+ });
4177
4239
  for (var i = 1; i < textParts.length; i++) {
4178
4240
  if (textParts[i][0] === '0') textarr.push({
4179
- text: textParts[i].substring(1)
4180
- });else if (textParts[i][0] === '1' && multilineVars.setfont[1]) textarr.push({
4181
- font: multilineVars.setfont[1],
4182
- text: textParts[i].substring(1)
4183
- });else if (textParts[i][0] === '2' && multilineVars.setfont[2]) textarr.push({
4184
- font: multilineVars.setfont[2],
4185
- text: textParts[i].substring(1)
4186
- });else if (textParts[i][0] === '3' && multilineVars.setfont[3]) textarr.push({
4187
- font: multilineVars.setfont[3],
4188
- text: textParts[i].substring(1)
4189
- });else if (textParts[i][0] === '4' && multilineVars.setfont[4]) textarr.push({
4190
- font: multilineVars.setfont[4],
4191
- text: textParts[i].substring(1)
4192
- });else textarr[textarr.length - 1].text += '$' + textParts[i];
4193
- }
4194
- if (textarr.length > 1) return textarr;
4195
- }
4196
- return textstr;
4241
+ text: textParts[i].substring(1).replace(/\x03/g, "$$")
4242
+ });else {
4243
+ var whichFont = parseInt(textParts[i][0], 10);
4244
+ if (multilineVars.setfont[whichFont]) textarr.push({
4245
+ font: multilineVars.setfont[whichFont],
4246
+ text: textParts[i].substring(1).replace(/\x03/g, "$$")
4247
+ });else textarr[textarr.length - 1].text += '$' + textParts[i].replace(/\x03/g, "$$");
4248
+ }
4249
+ }
4250
+ return textarr;
4251
+ }
4252
+ return textstr.replace(/\x03/g, "$$");
4197
4253
  };
4198
4254
  var positionChoices = ['auto', 'above', 'below', 'hidden'];
4199
4255
  parseDirective.addDirective = function (str) {
@@ -4241,6 +4297,9 @@ var parseDirective = {};
4241
4297
  case "jazzchords":
4242
4298
  tune.formatting.jazzchords = true;
4243
4299
  break;
4300
+ case "accentAbove":
4301
+ tune.formatting.accentAbove = true;
4302
+ break;
4244
4303
  case "germanAlphabet":
4245
4304
  tune.formatting.germanAlphabet = true;
4246
4305
  break;
@@ -4432,7 +4491,7 @@ var parseDirective = {};
4432
4491
  if (sfTokens.length >= 4) {
4433
4492
  if (sfTokens[0].token === '-' && sfTokens[1].type === 'number') {
4434
4493
  var sfNum = parseInt(sfTokens[1].token);
4435
- if (sfNum >= 1 && sfNum <= 4) {
4494
+ if (sfNum >= 1 && sfNum <= 9) {
4436
4495
  if (!multilineVars.setfont) multilineVars.setfont = [];
4437
4496
  sfTokens.shift();
4438
4497
  sfTokens.shift();
@@ -4750,17 +4809,15 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
4750
4809
  parseDirective.initialize(tokenizer, warn, multilineVars, tune, tuneBuilder);
4751
4810
  };
4752
4811
  this.reset(tokenizer, warn, multilineVars, tune);
4753
- this.setTitle = function (title) {
4754
- if (multilineVars.hasMainTitle) tuneBuilder.addSubtitle(tokenizer.translateString(tokenizer.stripComment(title)), {
4812
+ this.setTitle = function (title, origSize) {
4813
+ if (multilineVars.hasMainTitle) tuneBuilder.addSubtitle(title, {
4755
4814
  startChar: multilineVars.iChar,
4756
- endChar: multilineVars.iChar + title.length + 2
4815
+ endChar: multilineVars.iChar + origSize + 2
4757
4816
  }); // display secondary title
4758
4817
  else {
4759
- var titleStr = tokenizer.translateString(tokenizer.theReverser(tokenizer.stripComment(title)));
4760
- if (multilineVars.titlecaps) titleStr = titleStr.toUpperCase();
4761
- tuneBuilder.addMetaText("title", titleStr, {
4818
+ tuneBuilder.addMetaText("title", title, {
4762
4819
  startChar: multilineVars.iChar,
4763
- endChar: multilineVars.iChar + title.length + 2
4820
+ endChar: multilineVars.iChar + origSize + 2
4764
4821
  });
4765
4822
  multilineVars.hasMainTitle = true;
4766
4823
  }
@@ -5120,12 +5177,13 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
5120
5177
  if (result.foundKey && tuneBuilder.hasBeginMusic()) tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
5121
5178
  return [e - i + 1 + ws];
5122
5179
  case "[P:":
5180
+ var part = parseDirective.parseFontChangeLine(line.substring(i + 3, e));
5123
5181
  if (startLine || tune.lines.length <= tune.lineNum) multilineVars.partForNextLine = {
5124
- title: line.substring(i + 3, e),
5182
+ title: part,
5125
5183
  startChar: startChar,
5126
5184
  endChar: endChar
5127
5185
  };else tuneBuilder.appendElement('part', startChar, endChar, {
5128
- title: line.substring(i + 3, e)
5186
+ title: part
5129
5187
  });
5130
5188
  return [e - i + 1 + ws];
5131
5189
  case "[L:":
@@ -5216,28 +5274,34 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
5216
5274
  };
5217
5275
  this.parseHeader = function (line) {
5218
5276
  var field = metaTextHeaders[line[0]];
5219
- if (field !== undefined) {
5220
- if (field === 'unalignedWords') tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line.substring(2)))), {
5277
+ var origSize = line.length - 2;
5278
+ var restOfLine = tokenizer.translateString(tokenizer.stripComment(line.substring(2)));
5279
+ if (field === 'unalignedWords' || field === 'notes') {
5280
+ // These fields can be multi-line
5281
+ tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(restOfLine), {
5221
5282
  startChar: multilineVars.iChar,
5222
5283
  endChar: multilineVars.iChar + line.length
5223
- });else tuneBuilder.addMetaText(field, tokenizer.translateString(tokenizer.stripComment(line.substring(2))), {
5284
+ });
5285
+ } else if (field !== undefined) {
5286
+ // these fields are single line
5287
+ tuneBuilder.addMetaText(field, parseDirective.parseFontChangeLine(restOfLine), {
5224
5288
  startChar: multilineVars.iChar,
5225
5289
  endChar: multilineVars.iChar + line.length
5226
5290
  });
5227
- return {};
5228
5291
  } else {
5229
5292
  var startChar = multilineVars.iChar;
5230
5293
  var endChar = startChar + line.length;
5231
5294
  switch (line[0]) {
5232
5295
  case 'H':
5233
- tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), {
5296
+ // History is a little different because once it starts it continues until another header field is encountered
5297
+ tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(restOfLine), {
5234
5298
  startChar: multilineVars.iChar,
5235
5299
  endChar: multilineVars.iChar + line.length
5236
5300
  });
5237
5301
  line = tokenizer.peekLine();
5238
5302
  while (line && line[1] !== ':') {
5239
5303
  tokenizer.nextLine();
5240
- tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line)), {
5304
+ tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line))), {
5241
5305
  startChar: multilineVars.iChar,
5242
5306
  endChar: multilineVars.iChar + line.length
5243
5307
  });
@@ -5262,11 +5326,11 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
5262
5326
  break;
5263
5327
  case 'P':
5264
5328
  // TODO-PER: There is more to do with parts, but the writer doesn't care.
5265
- if (multilineVars.is_in_header) tuneBuilder.addMetaText("partOrder", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), {
5329
+ if (multilineVars.is_in_header) tuneBuilder.addMetaText("partOrder", parseDirective.parseFontChangeLine(restOfLine), {
5266
5330
  startChar: multilineVars.iChar,
5267
5331
  endChar: multilineVars.iChar + line.length
5268
5332
  });else multilineVars.partForNextLine = {
5269
- title: tokenizer.translateString(tokenizer.stripComment(line.substring(2))),
5333
+ title: restOfLine,
5270
5334
  startChar: startChar,
5271
5335
  endChar: endChar
5272
5336
  };
@@ -5278,7 +5342,8 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
5278
5342
  }
5279
5343
  break;
5280
5344
  case 'T':
5281
- this.setTitle(line.substring(2));
5345
+ if (multilineVars.titlecaps) restOfLine = restOfLine.toUpperCase();
5346
+ this.setTitle(parseDirective.parseFontChangeLine(tokenizer.theReverser(restOfLine)), origSize);
5282
5347
  break;
5283
5348
  case 'U':
5284
5349
  this.addUserDefinition(line, 2, line.length);
@@ -8718,9 +8783,67 @@ var Tokenizer = function Tokenizer(lines, multilineVars) {
8718
8783
  index: index
8719
8784
  };
8720
8785
  };
8786
+
8787
+ //
8788
+ // MAE 10 Jan 2023 - For better handling of tunes that have tune numbers in front of them.
8789
+ //
8790
+ // Previous version would take:
8791
+ // 21. Woman of the House, The
8792
+ // and return:
8793
+ // The 21. Woman of the House
8794
+ //
8795
+ // This fix results in:
8796
+ // 21. The Woman of the House
8797
+ //
8798
+ // Also added additional checks and handlers for lower case ", the" and ", a" since I found several tune collections with those tune name constructs
8799
+ //
8800
+ // Find an optional title number at the start of a tune title
8801
+ function getTitleNumber(str) {
8802
+ var regex = /^(\d+)\./;
8803
+
8804
+ // Use the exec method to search for the pattern in the string
8805
+ var match = regex.exec(str);
8806
+
8807
+ // Check if a match is found
8808
+ if (match) {
8809
+ // The matched number is captured in the first group (index 1)
8810
+ var foundNumber = match[1];
8811
+ return foundNumber;
8812
+ } else {
8813
+ // Return null if no match is found
8814
+ return null;
8815
+ }
8816
+ }
8817
+ var thePatterns = [{
8818
+ match: /,\s*[Tt]he$/,
8819
+ replace: "The "
8820
+ }, {
8821
+ match: /,\s*[Aa]$/,
8822
+ replace: "A "
8823
+ }, {
8824
+ match: /,\s*[Aa]n$/,
8825
+ replace: "An "
8826
+ }];
8721
8827
  this.theReverser = function (str) {
8722
- if (parseCommon.endsWith(str, ", The")) return "The " + str.substring(0, str.length - 5);
8723
- if (parseCommon.endsWith(str, ", A")) return "A " + str.substring(0, str.length - 3);
8828
+ for (var i = 0; i < thePatterns.length; i++) {
8829
+ var thisPattern = thePatterns[i];
8830
+ var match = str.match(thisPattern.match);
8831
+ if (match) {
8832
+ var theTitleNumber = getTitleNumber(str);
8833
+ if (theTitleNumber) {
8834
+ //console.log("theReverser The titlenumber:"+theTitleNumber);
8835
+
8836
+ str = str.replace(theTitleNumber + ".", "");
8837
+ str = str.trim();
8838
+ }
8839
+ var len = match[0].length;
8840
+ var result = thisPattern.replace + str.substring(0, str.length - len);
8841
+ if (theTitleNumber) {
8842
+ result = theTitleNumber + ". " + result;
8843
+ }
8844
+ return result;
8845
+ }
8846
+ }
8724
8847
  return str;
8725
8848
  };
8726
8849
  this.stripComment = function (str) {
@@ -9154,6 +9277,7 @@ module.exports = transposeChordName;
9154
9277
 
9155
9278
  var parseKeyVoice = __webpack_require__(/*! ../parse/abc_parse_key_voice */ "./src/parse/abc_parse_key_voice.js");
9156
9279
  var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/abc_common.js");
9280
+ var parseDirective = __webpack_require__(/*! ./abc_parse_directive */ "./src/parse/abc_parse_directive.js");
9157
9281
  var TuneBuilder = function TuneBuilder(tune) {
9158
9282
  var self = this;
9159
9283
  this.setVisualTranspose = function (visualTranspose) {
@@ -9313,6 +9437,8 @@ var TuneBuilder = function TuneBuilder(tune) {
9313
9437
  this.cleanUp = function (barsperstaff, staffnonote, currSlur) {
9314
9438
  this.closeLine(); // Close the last line.
9315
9439
  delete tune.runningFonts;
9440
+ simplifyMetaText(tune);
9441
+ //addRichTextToAnnotationsAndLyrics(tune)
9316
9442
 
9317
9443
  // If the tempo was created with a string like "Allegro", then the duration of a beat needs to be set at the last moment, when it is most likely known.
9318
9444
  if (tune.metaText.tempo && tune.metaText.tempo.bpm && !tune.metaText.tempo.duration) tune.metaText.tempo.duration = [tune.getBeatLength()];
@@ -10047,7 +10173,15 @@ var TuneBuilder = function TuneBuilder(tune) {
10047
10173
  tune.metaText[key] = value;
10048
10174
  tune.metaTextInfo[key] = info;
10049
10175
  } else {
10050
- tune.metaText[key] += "\n" + value;
10176
+ if (typeof tune.metaText[key] === 'string' && typeof value === 'string') tune.metaText[key] += "\n" + value;else {
10177
+ if (tune.metaText[key] === 'string') tune.metaText[key] = [{
10178
+ text: tune.metaText[key]
10179
+ }];
10180
+ if (typeof value === 'string') value = [{
10181
+ text: value
10182
+ }];
10183
+ tune.metaText[key] = tune.metaText[key].concat(value);
10184
+ }
10051
10185
  tune.metaTextInfo[key].endChar = info.endChar;
10052
10186
  }
10053
10187
  };
@@ -10065,6 +10199,46 @@ var TuneBuilder = function TuneBuilder(tune) {
10065
10199
  tune.metaTextInfo[key] = info;
10066
10200
  };
10067
10201
  };
10202
+ function isArrayOfStrings(arr) {
10203
+ if (!arr) return false;
10204
+ if (typeof arr === "string") return false;
10205
+ var str = '';
10206
+ for (var i = 0; i < arr.length; i++) {
10207
+ if (typeof arr[i] !== 'string') return false;
10208
+ }
10209
+ return true;
10210
+ }
10211
+ function simplifyMetaText(tune) {
10212
+ if (isArrayOfStrings(tune.metaText.notes)) tune.metaText.notes = tune.metaText.notes.join("\n");
10213
+ if (isArrayOfStrings(tune.metaText.history)) tune.metaText.history = tune.metaText.history.join("\n");
10214
+ }
10215
+ function addRichTextToAnnotationsAndLyrics(tune) {
10216
+ var lines = tune.lines;
10217
+ for (var i = 0; i < lines.length; i++) {
10218
+ if (lines[i].staff !== undefined) {
10219
+ for (var s = 0; s < lines[i].staff.length; s++) {
10220
+ for (var v = 0; v < lines[i].staff[s].voices.length; v++) {
10221
+ var voice = lines[i].staff[s].voices[v];
10222
+ for (var n = 0; n < voice.length; n++) {
10223
+ var element = voice[n];
10224
+ if (element.chord) {
10225
+ for (var c = 0; c < element.chord.length; c++) {
10226
+ element.chord[c].name = parseDirective.parseFontChangeLine(element.chord[c].name);
10227
+ console.log(element.chord[c].name);
10228
+ }
10229
+ }
10230
+ if (element.lyric) {
10231
+ for (var l = 0; l < element.lyric.length; l++) {
10232
+ element.lyric[l].syllable = parseDirective.parseFontChangeLine(element.lyric[l].syllable);
10233
+ console.log(element.lyric[l].syllable);
10234
+ }
10235
+ }
10236
+ }
10237
+ }
10238
+ }
10239
+ }
10240
+ }
10241
+ }
10068
10242
  module.exports = TuneBuilder;
10069
10243
 
10070
10244
  /***/ }),
@@ -15046,6 +15220,8 @@ function SynthController() {
15046
15220
  self.isLoading = false;
15047
15221
  self.load = function (selector, cursorControl, visualOptions) {
15048
15222
  if (!visualOptions) visualOptions = {};
15223
+ if (visualOptions.displayPlay === undefined) visualOptions.displayPlay = true;
15224
+ if (visualOptions.displayProgress === undefined) visualOptions.displayProgress = true;
15049
15225
  self.control = new CreateSynthControl(selector, {
15050
15226
  loopHandler: visualOptions.displayLoop ? self.toggleLoop : undefined,
15051
15227
  restartHandler: visualOptions.displayRestart ? self.restart : undefined,
@@ -15063,7 +15239,7 @@ function SynthController() {
15063
15239
  self.setTune = function (visualObj, userAction, audioParams) {
15064
15240
  self.visualObj = visualObj;
15065
15241
  self.disable(false);
15066
- self.options = audioParams;
15242
+ self.options = audioParams ? audioParams : {};
15067
15243
  if (self.control) {
15068
15244
  self.pause();
15069
15245
  self.setProgress(0, 1);
@@ -15195,7 +15371,7 @@ function SynthController() {
15195
15371
  };
15196
15372
  self._randomAccess = function (ev) {
15197
15373
  var background = ev.target.classList.contains('abcjs-midi-progress-indicator') ? ev.target.parentNode : ev.target;
15198
- var percent = (ev.x - background.offsetLeft) / background.offsetWidth;
15374
+ var percent = (ev.x - background.getBoundingClientRect().left) / background.offsetWidth;
15199
15375
  if (percent < 0) percent = 0;
15200
15376
  if (percent > 1) percent = 1;
15201
15377
  self.seek(percent);
@@ -15337,87 +15513,6 @@ module.exports = SynthSequence;
15337
15513
 
15338
15514
  /***/ }),
15339
15515
 
15340
- /***/ "./src/tablatures/instruments/guitar/guitar-patterns.js":
15341
- /*!**************************************************************!*\
15342
- !*** ./src/tablatures/instruments/guitar/guitar-patterns.js ***!
15343
- \**************************************************************/
15344
- /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
15345
-
15346
- var StringPatterns = __webpack_require__(/*! ../string-patterns */ "./src/tablatures/instruments/string-patterns.js");
15347
- function GuitarPatterns(plugin) {
15348
- this.tuning = plugin._super.params.tuning;
15349
- if (!this.tuning) {
15350
- this.tuning = ['E,', 'A,', 'D', 'G', 'B', 'e'];
15351
- }
15352
- plugin.tuning = this.tuning;
15353
- this.strings = new StringPatterns(plugin);
15354
- }
15355
- GuitarPatterns.prototype.notesToNumber = function (notes, graces) {
15356
- var converter = this.strings;
15357
- return converter.notesToNumber(notes, graces);
15358
- };
15359
- GuitarPatterns.prototype.stringToPitch = function (stringNumber) {
15360
- var converter = this.strings;
15361
- return converter.stringToPitch(stringNumber);
15362
- };
15363
- module.exports = GuitarPatterns;
15364
-
15365
- /***/ }),
15366
-
15367
- /***/ "./src/tablatures/instruments/guitar/tab-guitar.js":
15368
- /*!*********************************************************!*\
15369
- !*** ./src/tablatures/instruments/guitar/tab-guitar.js ***!
15370
- \*********************************************************/
15371
- /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
15372
-
15373
- /*
15374
- Emit tab for Guitar staff
15375
- */
15376
- var StringTablature = __webpack_require__(/*! ../string-tablature */ "./src/tablatures/instruments/string-tablature.js");
15377
- var TabCommon = __webpack_require__(/*! ../../tab-common */ "./src/tablatures/tab-common.js");
15378
- var TabRenderer = __webpack_require__(/*! ../../tab-renderer */ "./src/tablatures/tab-renderer.js");
15379
- var GuitarPatterns = __webpack_require__(/*! ./guitar-patterns */ "./src/tablatures/instruments/guitar/guitar-patterns.js");
15380
-
15381
- /**
15382
- * upon init mainly store provided instances for later usage
15383
- * @param {*} abcTune the parsed tune AST tree
15384
- * @param {*} tuneNumber the parsed tune AST tree
15385
- * @param {*} params complementary args provided to Tablature Plugin
15386
- */
15387
- Plugin.prototype.init = function (abcTune, tuneNumber, params) {
15388
- var _super = new TabCommon(abcTune, tuneNumber, params);
15389
- this._super = _super;
15390
- this.abcTune = abcTune;
15391
- this.linePitch = 3;
15392
- this.nbLines = 6;
15393
- this.isTabBig = true;
15394
- this.capo = params.capo;
15395
- this.transpose = params.visualTranspose;
15396
- this.tablature = new StringTablature(this.nbLines, this.linePitch);
15397
- var semantics = new GuitarPatterns(this);
15398
- this.semantics = semantics;
15399
- };
15400
- Plugin.prototype.render = function (renderer, line, staffIndex) {
15401
- if (this._super.inError) return;
15402
- if (this.tablature.bypass(line)) return;
15403
- var rndrer = new TabRenderer(this, renderer, line, staffIndex);
15404
- rndrer.doLayout();
15405
- };
15406
- function Plugin() {}
15407
-
15408
- //
15409
- // Tablature plugin definition
15410
- //
15411
- var AbcGuitarTab = function AbcGuitarTab() {
15412
- return {
15413
- name: 'GuitarTab',
15414
- tablature: Plugin
15415
- };
15416
- };
15417
- module.exports = AbcGuitarTab;
15418
-
15419
- /***/ }),
15420
-
15421
15516
  /***/ "./src/tablatures/instruments/string-patterns.js":
15422
15517
  /*!*******************************************************!*\
15423
15518
  !*** ./src/tablatures/instruments/string-patterns.js ***!
@@ -15658,6 +15753,17 @@ StringPatterns.prototype.tabInfos = function (plugin) {
15658
15753
  return '';
15659
15754
  };
15660
15755
 
15756
+ // MAE 27 Nov 2023
15757
+ StringPatterns.prototype.suppress = function (plugin) {
15758
+ var _super = plugin._super;
15759
+ var suppress = _super.params.suppress;
15760
+ if (suppress) {
15761
+ return true;
15762
+ }
15763
+ return false;
15764
+ };
15765
+ // MAE 27 Nov 2023 End
15766
+
15661
15767
  /**
15662
15768
  * Common patterns for all string instruments
15663
15769
  * @param {} plugin
@@ -16032,16 +16138,43 @@ module.exports = TabNotes;
16032
16138
 
16033
16139
  /***/ }),
16034
16140
 
16035
- /***/ "./src/tablatures/instruments/violin/tab-violin.js":
16036
- /*!*********************************************************!*\
16037
- !*** ./src/tablatures/instruments/violin/tab-violin.js ***!
16038
- \*********************************************************/
16141
+ /***/ "./src/tablatures/instruments/tab-string-patterns.js":
16142
+ /*!***********************************************************!*\
16143
+ !*** ./src/tablatures/instruments/tab-string-patterns.js ***!
16144
+ \***********************************************************/
16145
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
16146
+
16147
+ var StringPatterns = __webpack_require__(/*! ./string-patterns */ "./src/tablatures/instruments/string-patterns.js");
16148
+ function TabStringPatterns(plugin, defaultTuning) {
16149
+ this.tuning = plugin._super.params.tuning;
16150
+ if (!this.tuning) {
16151
+ this.tuning = defaultTuning;
16152
+ }
16153
+ plugin.tuning = this.tuning;
16154
+ this.strings = new StringPatterns(plugin);
16155
+ }
16156
+ TabStringPatterns.prototype.notesToNumber = function (notes, graces) {
16157
+ var converter = this.strings;
16158
+ return converter.notesToNumber(notes, graces);
16159
+ };
16160
+ TabStringPatterns.prototype.stringToPitch = function (stringNumber) {
16161
+ var converter = this.strings;
16162
+ return converter.stringToPitch(stringNumber);
16163
+ };
16164
+ module.exports = TabStringPatterns;
16165
+
16166
+ /***/ }),
16167
+
16168
+ /***/ "./src/tablatures/instruments/tab-string.js":
16169
+ /*!**************************************************!*\
16170
+ !*** ./src/tablatures/instruments/tab-string.js ***!
16171
+ \**************************************************/
16039
16172
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
16040
16173
 
16041
- var StringTablature = __webpack_require__(/*! ../string-tablature */ "./src/tablatures/instruments/string-tablature.js");
16042
- var TabCommon = __webpack_require__(/*! ../../tab-common */ "./src/tablatures/tab-common.js");
16043
- var TabRenderer = __webpack_require__(/*! ../../tab-renderer */ "./src/tablatures/tab-renderer.js");
16044
- var ViolinPatterns = __webpack_require__(/*! ./violin-patterns */ "./src/tablatures/instruments/violin/violin-patterns.js");
16174
+ var StringTablature = __webpack_require__(/*! ./string-tablature */ "./src/tablatures/instruments/string-tablature.js");
16175
+ var TabCommon = __webpack_require__(/*! ../tab-common */ "./src/tablatures/tab-common.js");
16176
+ var TabRenderer = __webpack_require__(/*! ../tab-renderer */ "./src/tablatures/tab-renderer.js");
16177
+ var TabStringPatterns = __webpack_require__(/*! ./tab-string-patterns */ "./src/tablatures/instruments/tab-string-patterns.js");
16045
16178
 
16046
16179
  /**
16047
16180
  * upon init mainly store provided instances for later usage
@@ -16049,17 +16182,19 @@ var ViolinPatterns = __webpack_require__(/*! ./violin-patterns */ "./src/tablatu
16049
16182
  * @param {*} tuneNumber the parsed tune AST tree
16050
16183
  * @param {*} params complementary args provided to Tablature Plugin
16051
16184
  */
16052
- Plugin.prototype.init = function (abcTune, tuneNumber, params) {
16185
+ Plugin.prototype.init = function (abcTune, tuneNumber, params, staffNumber, tabSettings) {
16053
16186
  var _super = new TabCommon(abcTune, tuneNumber, params);
16054
16187
  this.abcTune = abcTune;
16055
16188
  this._super = _super;
16056
16189
  this.linePitch = 3;
16057
- this.nbLines = 4;
16058
- this.isTabBig = false;
16190
+ this.nbLines = tabSettings.defaultTuning.length;
16191
+ this.isTabBig = tabSettings.isTabBig;
16192
+ this.tabSymbolOffset = tabSettings.tabSymbolOffset;
16059
16193
  this.capo = params.capo;
16060
16194
  this.transpose = params.visualTranspose;
16195
+ this.hideTabSymbol = params.hideTabSymbol;
16061
16196
  this.tablature = new StringTablature(this.nbLines, this.linePitch);
16062
- var semantics = new ViolinPatterns(this);
16197
+ var semantics = new TabStringPatterns(this, tabSettings.defaultTuning);
16063
16198
  this.semantics = semantics;
16064
16199
  };
16065
16200
  Plugin.prototype.render = function (renderer, line, staffIndex) {
@@ -16073,40 +16208,13 @@ function Plugin() {}
16073
16208
  //
16074
16209
  // Tablature plugin definition
16075
16210
  //
16076
- var AbcViolinTab = function AbcViolinTab() {
16211
+ var AbcStringTab = function AbcStringTab() {
16077
16212
  return {
16078
- name: 'ViolinTab',
16213
+ name: 'StringTab',
16079
16214
  tablature: Plugin
16080
16215
  };
16081
16216
  };
16082
- module.exports = AbcViolinTab;
16083
-
16084
- /***/ }),
16085
-
16086
- /***/ "./src/tablatures/instruments/violin/violin-patterns.js":
16087
- /*!**************************************************************!*\
16088
- !*** ./src/tablatures/instruments/violin/violin-patterns.js ***!
16089
- \**************************************************************/
16090
- /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
16091
-
16092
- var StringPatterns = __webpack_require__(/*! ../string-patterns */ "./src/tablatures/instruments/string-patterns.js");
16093
- function ViolinPatterns(plugin) {
16094
- this.tuning = plugin._super.params.tuning;
16095
- if (!this.tuning) {
16096
- this.tuning = ['G,', 'D', 'A', 'e'];
16097
- }
16098
- plugin.tuning = this.tuning;
16099
- this.strings = new StringPatterns(plugin);
16100
- }
16101
- ViolinPatterns.prototype.notesToNumber = function (notes, graces) {
16102
- var converter = this.strings;
16103
- return converter.notesToNumber(notes, graces);
16104
- };
16105
- ViolinPatterns.prototype.stringToPitch = function (stringNumber) {
16106
- var converter = this.strings;
16107
- return converter.stringToPitch(stringNumber);
16108
- };
16109
- module.exports = ViolinPatterns;
16217
+ module.exports = AbcStringTab;
16110
16218
 
16111
16219
  /***/ }),
16112
16220
 
@@ -16175,13 +16283,20 @@ function buildTabAbsolute(plugin, absX, relX) {
16175
16283
  icon: tabIcon,
16176
16284
  Ypos: tabYPos
16177
16285
  };
16178
- var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0);
16179
- tabAbsolute.x = absX;
16180
- var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab");
16181
- tabRelative.x = relX;
16182
- tabAbsolute.children.push(tabRelative);
16183
- if (tabAbsolute.abcelem.el_type == 'tab') {
16184
- tabRelative.pitch = tabYPos;
16286
+
16287
+ // Offset the TAB symbol position if specified in the tab description
16288
+ tabYPos += plugin.tabSymbolOffset;
16289
+
16290
+ // For tablature like whistle tab where you want the TAB symbol hidden
16291
+ if (!plugin.hideTabSymbol) {
16292
+ var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0);
16293
+ tabAbsolute.x = absX;
16294
+ var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab");
16295
+ tabRelative.x = relX;
16296
+ tabAbsolute.children.push(tabRelative);
16297
+ if (tabAbsolute.abcelem.el_type == 'tab') {
16298
+ tabRelative.pitch = tabYPos;
16299
+ }
16185
16300
  }
16186
16301
  return tabAbsolute;
16187
16302
  }
@@ -16498,12 +16613,23 @@ function buildTabName(self, dest) {
16498
16613
  var controller = self.renderer.controller;
16499
16614
  var textSize = controller.getTextSize;
16500
16615
  var tabName = stringSemantics.tabInfos(self.plugin);
16501
- var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname');
16502
- dest.tabNameInfos = {
16503
- textSize: size,
16504
- name: tabName
16505
- };
16506
- return size.height;
16616
+ var suppress = stringSemantics.suppress(self.plugin);
16617
+ var doDraw = true;
16618
+ if (suppress) {
16619
+ doDraw = false;
16620
+ }
16621
+ if (doDraw) {
16622
+ var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname');
16623
+ dest.tabNameInfos = {
16624
+ textSize: {
16625
+ height: size.height,
16626
+ width: size.width
16627
+ },
16628
+ name: tabName
16629
+ };
16630
+ return size.height;
16631
+ }
16632
+ return 0;
16507
16633
  }
16508
16634
 
16509
16635
  /**
@@ -16675,8 +16801,10 @@ TabRenderer.prototype.doLayout = function () {
16675
16801
  if (ii > 0) tabVoice.duplicate = true;
16676
16802
  var nameHeight = buildTabName(this, tabVoice) / spacing.STEP;
16677
16803
  nameHeight = Math.max(nameHeight, 1); // If there is no label for the tab line, then there needs to be a little padding
16678
- staffGroup.staffs[this.staffIndex].top += nameHeight;
16679
- staffGroup.height += nameHeight * spacing.STEP;
16804
+ // This was pushing down the top staff by the tab label height
16805
+ //staffGroup.staffs[this.staffIndex].top += nameHeight;
16806
+ staffGroup.staffs[this.staffIndex].top += 1;
16807
+ staffGroup.height += nameHeight;
16680
16808
  tabVoice.staff = staffGroupInfos;
16681
16809
  var tabVoiceIndex = voices.length;
16682
16810
  voices.splice(voices.length, 0, tabVoice);
@@ -16822,6 +16950,7 @@ var AbstractEngraver = function AbstractEngraver(getTextSize, tuneNumber, option
16822
16950
  this.percmap = options.percmap;
16823
16951
  this.initialClef = options.initialClef;
16824
16952
  this.jazzchords = !!options.jazzchords;
16953
+ this.accentAbove = !!options.accentAbove;
16825
16954
  this.germanAlphabet = !!options.germanAlphabet;
16826
16955
  this.reset();
16827
16956
  };
@@ -17618,7 +17747,7 @@ AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaf
17618
17747
  roomtaken += this.addGraceNotes(elem, voice, abselem, notehead, this.stemHeight * this.voiceScale, this.isBagpipes, roomtaken);
17619
17748
  }
17620
17749
  if (elem.decoration) {
17621
- this.decoration.createDecoration(voice, elem.decoration, abselem.top, notehead ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals);
17750
+ this.decoration.createDecoration(voice, elem.decoration, abselem.top, notehead ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals, this.accentAbove);
17622
17751
  }
17623
17752
  if (elem.barNumber) {
17624
17753
  abselem.addFixed(new RelativeElement(elem.barNumber, -10, 0, 0, {
@@ -17790,7 +17919,7 @@ AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff)
17790
17919
  abselem.addRight(anchor);
17791
17920
  }
17792
17921
  if (elem.decoration) {
17793
- this.decoration.createDecoration(voice, elem.decoration, 12, thick ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals);
17922
+ this.decoration.createDecoration(voice, elem.decoration, 12, thick ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals, this.accentAbove);
17794
17923
  }
17795
17924
  if (thick) {
17796
17925
  dx += 4; //3 hardcoded;
@@ -17860,100 +17989,121 @@ var addChord = function addChord(getTextSize, abselem, elem, roomTaken, roomTake
17860
17989
  for (var i = 0; i < elem.chord.length; i++) {
17861
17990
  var pos = elem.chord[i].position;
17862
17991
  var rel_position = elem.chord[i].rel_position;
17863
- var chords = elem.chord[i].name.split("\n");
17864
- for (var j = chords.length - 1; j >= 0; j--) {
17865
- // parse these in opposite order because we place them from bottom to top.
17866
- var chord = chords[j];
17867
- var x = 0;
17868
- var y;
17869
- var font;
17870
- var klass;
17871
- if (pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position) {
17872
- font = 'annotationfont';
17873
- klass = "annotation";
17874
- } else {
17875
- font = 'gchordfont';
17876
- klass = "chord";
17877
- chord = translateChord(chord, jazzchords, germanAlphabet);
17878
- }
17879
- var attr = getTextSize.attr(font, klass);
17880
- var dim = getTextSize.calc(chord, font, klass);
17881
- var chordWidth = dim.width;
17882
- var chordHeight = dim.height / spacing.STEP;
17883
- switch (pos) {
17884
- case "left":
17885
- roomTaken += chordWidth + 7;
17886
- x = -roomTaken; // TODO-PER: This is just a guess from trial and error
17887
- y = elem.averagepitch;
17888
- abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, {
17889
- type: "text",
17890
- height: chordHeight,
17891
- dim: attr,
17892
- position: "left"
17893
- }));
17894
- break;
17895
- case "right":
17896
- roomTakenRight += 4;
17897
- x = roomTakenRight; // TODO-PER: This is just a guess from trial and error
17898
- y = elem.averagepitch;
17899
- abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, {
17900
- type: "text",
17901
- height: chordHeight,
17902
- dim: attr,
17903
- position: "right"
17904
- }));
17905
- break;
17906
- case "below":
17907
- // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
17908
- abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
17992
+ var isAnnotation = pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position;
17993
+ var font;
17994
+ var klass;
17995
+ if (isAnnotation) {
17996
+ font = 'annotationfont';
17997
+ klass = "abcjs-annotation";
17998
+ } else {
17999
+ font = 'gchordfont';
18000
+ klass = "abcjs-chord";
18001
+ }
18002
+ var attr = getTextSize.attr(font, klass);
18003
+ var name = elem.chord[i].name;
18004
+ var ret;
18005
+ //console.log("chord",name)
18006
+ if (typeof name === "string") {
18007
+ ret = chordString(name, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet);
18008
+ roomTaken = ret.roomTaken;
18009
+ roomTakenRight = ret.roomTakenRight;
18010
+ } else {
18011
+ for (var j = 0; j < name.length; j++) {
18012
+ ret = chordString(name[j].text, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet);
18013
+ roomTaken = ret.roomTaken;
18014
+ roomTakenRight = ret.roomTakenRight;
18015
+ }
18016
+ }
18017
+ }
18018
+ return {
18019
+ roomTaken: roomTaken,
18020
+ roomTakenRight: roomTakenRight
18021
+ };
18022
+ };
18023
+ function chordString(chordString, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet) {
18024
+ var chords = chordString.split("\n");
18025
+ for (var j = chords.length - 1; j >= 0; j--) {
18026
+ // parse these in opposite order because we place them from bottom to top.
18027
+ var chord = chords[j];
18028
+ var x = 0;
18029
+ var y;
18030
+ if (!isAnnotation) chord = translateChord(chord, jazzchords, germanAlphabet);
18031
+ var dim = getTextSize.calc(chord, font, klass);
18032
+ var chordWidth = dim.width;
18033
+ var chordHeight = dim.height / spacing.STEP;
18034
+ switch (pos) {
18035
+ case "left":
18036
+ roomTaken += chordWidth + 7;
18037
+ x = -roomTaken; // TODO-PER: This is just a guess from trial and error
18038
+ y = elem.averagepitch;
18039
+ abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, {
18040
+ type: "text",
18041
+ height: chordHeight,
18042
+ dim: attr,
18043
+ position: "left"
18044
+ }));
18045
+ break;
18046
+ case "right":
18047
+ roomTakenRight += 4;
18048
+ x = roomTakenRight; // TODO-PER: This is just a guess from trial and error
18049
+ y = elem.averagepitch;
18050
+ abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, {
18051
+ type: "text",
18052
+ height: chordHeight,
18053
+ dim: attr,
18054
+ position: "right"
18055
+ }));
18056
+ break;
18057
+ case "below":
18058
+ // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
18059
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
18060
+ type: "text",
18061
+ position: "below",
18062
+ height: chordHeight,
18063
+ dim: attr,
18064
+ realWidth: chordWidth
18065
+ }));
18066
+ break;
18067
+ case "above":
18068
+ // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
18069
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
18070
+ type: "text",
18071
+ position: "above",
18072
+ height: chordHeight,
18073
+ dim: attr,
18074
+ realWidth: chordWidth
18075
+ }));
18076
+ break;
18077
+ default:
18078
+ if (rel_position) {
18079
+ var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps
18080
+ abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, {
18081
+ position: "relative",
17909
18082
  type: "text",
17910
- position: "below",
17911
18083
  height: chordHeight,
17912
- dim: attr,
17913
- realWidth: chordWidth
18084
+ dim: attr
17914
18085
  }));
17915
- break;
17916
- case "above":
18086
+ } else {
17917
18087
  // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
17918
- abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
17919
- type: "text",
17920
- position: "above",
17921
- height: chordHeight,
17922
- dim: attr,
17923
- realWidth: chordWidth
17924
- }));
17925
- break;
17926
- default:
17927
- if (rel_position) {
17928
- var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps
17929
- abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, {
17930
- position: "relative",
17931
- type: "text",
18088
+ var pos2 = 'above';
18089
+ if (elem.positioning && elem.positioning.chordPosition) pos2 = elem.positioning.chordPosition;
18090
+ if (pos2 !== 'hidden') {
18091
+ abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, {
18092
+ type: "chord",
18093
+ position: pos2,
17932
18094
  height: chordHeight,
17933
- dim: attr
18095
+ dim: attr,
18096
+ realWidth: chordWidth
17934
18097
  }));
17935
- } else {
17936
- // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
17937
- var pos2 = 'above';
17938
- if (elem.positioning && elem.positioning.chordPosition) pos2 = elem.positioning.chordPosition;
17939
- if (pos2 !== 'hidden') {
17940
- abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, {
17941
- type: "chord",
17942
- position: pos2,
17943
- height: chordHeight,
17944
- dim: attr,
17945
- realWidth: chordWidth
17946
- }));
17947
- }
17948
18098
  }
17949
- }
18099
+ }
17950
18100
  }
17951
18101
  }
17952
18102
  return {
17953
18103
  roomTaken: roomTaken,
17954
18104
  roomTakenRight: roomTakenRight
17955
18105
  };
17956
- };
18106
+ }
17957
18107
  module.exports = addChord;
17958
18108
 
17959
18109
  /***/ }),
@@ -17982,10 +18132,11 @@ function addTextIf(rows, params, getTextSize) {
17982
18132
  font: params.font,
17983
18133
  anchor: params.anchor,
17984
18134
  startChar: params.info.startChar,
17985
- endChar: params.info.endChar
18135
+ endChar: params.info.endChar,
18136
+ 'dominant-baseline': params['dominant-baseline']
17986
18137
  };
17987
18138
  if (params.absElemType) attr.absElemType = params.absElemType;
17988
- if (!params.inGroup) attr.klass = params.klass;
18139
+ if (!params.inGroup && params.klass) attr.klass = params.klass;
17989
18140
  if (params.name) attr.name = params.name;
17990
18141
  rows.push(attr);
17991
18142
  // If there are blank lines they won't be counted by getTextSize, so just get the height of one line and multiply
@@ -18441,10 +18592,10 @@ var Decoration = function Decoration() {
18441
18592
  this.minTop = 12; // TODO-PER: this is assuming a 5-line staff. Pass that info in.
18442
18593
  this.minBottom = 0;
18443
18594
  };
18444
- var closeDecoration = function closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch) {
18595
+ var closeDecoration = function closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove) {
18445
18596
  var yPos;
18446
18597
  for (var i = 0; i < decoration.length; i++) {
18447
- if (decoration[i] === "staccato" || decoration[i] === "tenuto" || decoration[i] === "accent") {
18598
+ if (decoration[i] === "staccato" || decoration[i] === "tenuto" || decoration[i] === "accent" && !accentAbove) {
18448
18599
  var symbol = "scripts." + decoration[i];
18449
18600
  if (decoration[i] === "accent") symbol = "scripts.sforzato";
18450
18601
  if (yPos === undefined) yPos = dir === "down" ? pitch + 2 : minPitch - 2;else yPos = dir === "down" ? yPos + 2 : yPos - 2;
@@ -18553,7 +18704,7 @@ var compoundDecoration = function compoundDecoration(decoration, pitch, width, a
18553
18704
  }
18554
18705
  }
18555
18706
  };
18556
- var stackedDecoration = function stackedDecoration(decoration, width, abselem, yPos, positioning, minTop, minBottom) {
18707
+ var stackedDecoration = function stackedDecoration(decoration, width, abselem, yPos, positioning, minTop, minBottom, accentAbove) {
18557
18708
  function incrementPlacement(placement, height) {
18558
18709
  if (placement === 'above') yPos.above += height;else yPos.below -= height;
18559
18710
  }
@@ -18692,6 +18843,12 @@ var stackedDecoration = function stackedDecoration(decoration, width, abselem, y
18692
18843
  case "mark":
18693
18844
  abselem.klass = "mark";
18694
18845
  break;
18846
+ case "accent":
18847
+ if (accentAbove) {
18848
+ symbolDecoration("scripts.sforzato", positioning);
18849
+ hasOne = true;
18850
+ }
18851
+ break;
18695
18852
  }
18696
18853
  }
18697
18854
  return hasOne;
@@ -18766,7 +18923,7 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
18766
18923
  voice.addOther(new GlissandoElem(glissando.start, glissando.stop));
18767
18924
  }
18768
18925
  };
18769
- Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals) {
18926
+ Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals, accentAbove) {
18770
18927
  if (!positioning) positioning = {
18771
18928
  ornamentPosition: 'above',
18772
18929
  volumePosition: hasVocals ? 'above' : 'below',
@@ -18778,14 +18935,14 @@ Decoration.prototype.createDecoration = function (voice, decoration, pitch, widt
18778
18935
  compoundDecoration(decoration, pitch, width, abselem, dir);
18779
18936
 
18780
18937
  // treat staccato, accent, and tenuto first (may need to shift other markers)
18781
- var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch);
18938
+ var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove);
18782
18939
  // yPos is an object containing 'above' and 'below'. That is the placement of the next symbol on either side.
18783
18940
 
18784
18941
  yPos.above = Math.max(yPos.above, this.minTop);
18785
- var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom);
18786
- if (hasOne) {
18787
- // abselem.top = Math.max(yPos.above + 3, abselem.top); // TODO-PER: Not sure why we need this fudge factor.
18788
- }
18942
+ var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom, accentAbove);
18943
+ //if (hasOne) {
18944
+ // abselem.top = Math.max(yPos.above + 3, abselem.top); // TODO-PER: Not sure why we need this fudge factor.
18945
+ //}
18789
18946
  leftDecoration(decoration, abselem, roomtaken);
18790
18947
  };
18791
18948
  module.exports = Decoration;
@@ -19145,94 +19302,109 @@ module.exports = BeamElem;
19145
19302
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
19146
19303
 
19147
19304
  var addTextIf = __webpack_require__(/*! ../add-text-if */ "./src/write/creation/add-text-if.js");
19148
- function BottomText(metaText, width, isPrint, paddingLeft, spacing, getTextSize) {
19305
+ var richText = __webpack_require__(/*! ./rich-text */ "./src/write/creation/elements/rich-text.js");
19306
+ function BottomText(metaText, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) {
19149
19307
  this.rows = [];
19150
- if (metaText.unalignedWords && metaText.unalignedWords.length > 0) this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, getTextSize);
19151
- this.extraText(metaText, paddingLeft, spacing, getTextSize);
19308
+ if (metaText.unalignedWords && metaText.unalignedWords.length > 0) this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, shouldAddClasses, getTextSize);
19309
+ this.extraText(metaText, paddingLeft, spacing, shouldAddClasses, getTextSize);
19152
19310
  if (metaText.footer && isPrint) this.footer(metaText.footer, width, paddingLeft, getTextSize);
19153
19311
  }
19154
- BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spacing, getTextSize) {
19155
- var klass = 'meta-bottom unaligned-words';
19312
+ BottomText.prototype.unalignedWords = function (unalignedWords, marginLeft, spacing, shouldAddClasses, getTextSize) {
19313
+ var klass = shouldAddClasses ? 'abcjs-unaligned-words' : '';
19156
19314
  var defFont = 'wordsfont';
19157
- this.rows.push({
19158
- startGroup: "unalignedWords",
19159
- klass: 'abcjs-meta-bottom abcjs-unaligned-words',
19160
- name: "words"
19161
- });
19162
19315
  var space = getTextSize.calc("i", defFont, klass);
19163
19316
  this.rows.push({
19164
19317
  move: spacing.words
19165
19318
  });
19166
- for (var j = 0; j < unalignedWords.length; j++) {
19167
- if (unalignedWords[j] === '') this.rows.push({
19168
- move: space.height
19169
- });else if (typeof unalignedWords[j] === 'string') {
19170
- addTextIf(this.rows, {
19171
- marginLeft: paddingLeft,
19172
- text: unalignedWords[j],
19319
+ addMultiLine(this.rows, '', unalignedWords, marginLeft, defFont, "unalignedWords", "unalignedWords", klass, "unalignedWords", spacing, shouldAddClasses, getTextSize);
19320
+ this.rows.push({
19321
+ move: space.height
19322
+ });
19323
+ };
19324
+ function addSingleLine(rows, preface, text, marginLeft, klass, shouldAddClasses, getTextSize) {
19325
+ if (text) {
19326
+ if (preface) {
19327
+ if (typeof text === 'string') text = preface + text;else text = [{
19328
+ text: preface
19329
+ }].concat(text);
19330
+ }
19331
+ klass = shouldAddClasses ? 'abcjs-extra-text ' + klass : '';
19332
+ richText(rows, text, 'historyfont', klass, "description", marginLeft, {
19333
+ absElemType: "extraText",
19334
+ anchor: 'start'
19335
+ }, getTextSize);
19336
+ }
19337
+ }
19338
+ function addMultiLine(rows, preface, content, marginLeft, defFont, absElemType, groupName, klass, name, spacing, shouldAddClasses, getTextSize) {
19339
+ if (content) {
19340
+ klass = shouldAddClasses ? 'abcjs-extra-text ' + klass : '';
19341
+ var size = getTextSize.calc("A", defFont, klass);
19342
+ if (typeof content === 'string') {
19343
+ if (preface) content = preface + "\n" + content;
19344
+ addTextIf(rows, {
19345
+ marginLeft: marginLeft,
19346
+ text: content,
19173
19347
  font: defFont,
19174
- klass: klass,
19175
- inGroup: true,
19176
- name: "words"
19348
+ absElemType: "extraText",
19349
+ name: name,
19350
+ 'dominant-baseline': 'middle',
19351
+ klass: klass
19177
19352
  }, getTextSize);
19353
+ //rows.push({move: size.height*3/4})
19178
19354
  } else {
19179
- var largestY = 0;
19180
- var offsetX = 0;
19181
- for (var k = 0; k < unalignedWords[j].length; k++) {
19182
- var thisWord = unalignedWords[j][k];
19183
- var font = thisWord.font ? thisWord.font : defFont;
19184
- this.rows.push({
19185
- left: paddingLeft + offsetX,
19186
- text: thisWord.text,
19187
- font: font,
19355
+ rows.push({
19356
+ startGroup: groupName,
19357
+ klass: klass,
19358
+ name: name
19359
+ });
19360
+ rows.push({
19361
+ move: spacing.info
19362
+ });
19363
+ if (preface) {
19364
+ addTextIf(rows, {
19365
+ marginLeft: marginLeft,
19366
+ text: preface,
19367
+ font: defFont,
19368
+ absElemType: "extraText",
19369
+ name: name,
19370
+ 'dominant-baseline': 'middle'
19371
+ }, getTextSize);
19372
+ rows.push({
19373
+ move: size.height * 3 / 4
19374
+ });
19375
+ }
19376
+ for (var j = 0; j < content.length; j++) {
19377
+ richText(rows, content[j], defFont, '', name, marginLeft, {
19188
19378
  anchor: 'start'
19379
+ }, getTextSize);
19380
+ // TODO-PER: Hack! the string and rich lines should have used up the same amount of space without this.
19381
+ if (j < content.length - 1 && typeof content[j] === 'string' && typeof content[j + 1] !== 'string') rows.push({
19382
+ move: size.height * 3 / 4
19189
19383
  });
19190
- var size = getTextSize.calc(thisWord.text, defFont, klass);
19191
- largestY = Math.max(largestY, size.height);
19192
- offsetX += size.width;
19193
- // If the phrase ends in a space, then that is not counted in the width, so we need to add that in ourselves.
19194
- if (thisWord.text[thisWord.text.length - 1] === ' ') {
19195
- offsetX += space.width;
19196
- }
19197
19384
  }
19198
- this.rows.push({
19199
- move: largestY
19385
+ rows.push({
19386
+ endGroup: groupName,
19387
+ absElemType: absElemType,
19388
+ startChar: -1,
19389
+ endChar: -1,
19390
+ name: name
19391
+ });
19392
+ rows.push({
19393
+ move: size.height
19200
19394
  });
19201
19395
  }
19202
19396
  }
19203
- this.rows.push({
19204
- move: space.height * 2
19205
- });
19206
- this.rows.push({
19207
- endGroup: "unalignedWords",
19208
- absElemType: "unalignedWords",
19209
- startChar: -1,
19210
- endChar: -1,
19211
- name: "unalignedWords"
19212
- });
19213
- };
19214
- BottomText.prototype.extraText = function (metaText, marginLeft, spacing, getTextSize) {
19215
- var extraText = "";
19216
- if (metaText.book) extraText += "Book: " + metaText.book + "\n";
19217
- if (metaText.source) extraText += "Source: " + metaText.source + "\n";
19218
- if (metaText.discography) extraText += "Discography: " + metaText.discography + "\n";
19219
- if (metaText.notes) extraText += "Notes: " + metaText.notes + "\n";
19220
- if (metaText.transcription) extraText += "Transcription: " + metaText.transcription + "\n";
19221
- if (metaText.history) extraText += "History: " + metaText.history + "\n";
19222
- if (metaText['abc-copyright']) extraText += "Copyright: " + metaText['abc-copyright'] + "\n";
19223
- if (metaText['abc-creator']) extraText += "Creator: " + metaText['abc-creator'] + "\n";
19224
- if (metaText['abc-edited-by']) extraText += "Edited By: " + metaText['abc-edited-by'] + "\n";
19225
- if (extraText.length > 0) {
19226
- addTextIf(this.rows, {
19227
- marginLeft: marginLeft,
19228
- text: extraText,
19229
- font: 'historyfont',
19230
- klass: 'meta-bottom extra-text',
19231
- marginTop: spacing.info,
19232
- absElemType: "extraText",
19233
- name: "description"
19234
- }, getTextSize);
19235
- }
19397
+ }
19398
+ BottomText.prototype.extraText = function (metaText, marginLeft, spacing, shouldAddClasses, getTextSize) {
19399
+ addSingleLine(this.rows, "Book: ", metaText.book, marginLeft, 'abcjs-book', shouldAddClasses, getTextSize);
19400
+ addSingleLine(this.rows, "Source: ", metaText.source, marginLeft, 'abcjs-source', shouldAddClasses, getTextSize);
19401
+ addSingleLine(this.rows, "Discography: ", metaText.discography, marginLeft, 'abcjs-discography', shouldAddClasses, getTextSize);
19402
+ addMultiLine(this.rows, 'Notes:', metaText.notes, marginLeft, 'historyfont', "extraText", "notes", 'abcjs-notes', "description", spacing, shouldAddClasses, getTextSize);
19403
+ addSingleLine(this.rows, "Transcription: ", metaText.transcription, marginLeft, 'abcjs-transcription', shouldAddClasses, getTextSize);
19404
+ addMultiLine(this.rows, "History:", metaText.history, marginLeft, 'historyfont', "extraText", "history", 'abcjs-history', "description", spacing, shouldAddClasses, getTextSize);
19405
+ addSingleLine(this.rows, "Copyright: ", metaText['abc-copyright'], marginLeft, 'abcjs-copyright', shouldAddClasses, getTextSize);
19406
+ addSingleLine(this.rows, "Creator: ", metaText['abc-creator'], marginLeft, 'abcjs-creator', shouldAddClasses, getTextSize);
19407
+ addSingleLine(this.rows, "Edited By: ", metaText['abc-edited-by'], marginLeft, 'abcjs-edited-by', shouldAddClasses, getTextSize);
19236
19408
  };
19237
19409
  BottomText.prototype.footer = function (footer, width, paddingLeft, getTextSize) {
19238
19410
  var klass = 'header meta-bottom';
@@ -19574,6 +19746,76 @@ module.exports = RelativeElement;
19574
19746
 
19575
19747
  /***/ }),
19576
19748
 
19749
+ /***/ "./src/write/creation/elements/rich-text.js":
19750
+ /*!**************************************************!*\
19751
+ !*** ./src/write/creation/elements/rich-text.js ***!
19752
+ \**************************************************/
19753
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
19754
+
19755
+ var addTextIf = __webpack_require__(/*! ../add-text-if */ "./src/write/creation/add-text-if.js");
19756
+ function richText(rows, str, defFont, klass, name, paddingLeft, attr, getTextSize) {
19757
+ var space = getTextSize.calc("i", defFont, klass);
19758
+ if (str === '') {
19759
+ rows.push({
19760
+ move: space.height
19761
+ });
19762
+ } else {
19763
+ if (typeof str === 'string') {
19764
+ addTextIf(rows, {
19765
+ marginLeft: paddingLeft,
19766
+ text: str,
19767
+ font: defFont,
19768
+ klass: klass,
19769
+ marginTop: attr.marginTop,
19770
+ anchor: attr.anchor,
19771
+ absElemType: attr.absElemType,
19772
+ info: attr.info,
19773
+ name: name
19774
+ }, getTextSize);
19775
+ return;
19776
+ }
19777
+ if (attr.marginTop) rows.push({
19778
+ move: attr.marginTop
19779
+ });
19780
+ var largestY = 0;
19781
+ var gap = 0;
19782
+ var row = {
19783
+ left: paddingLeft,
19784
+ anchor: attr.anchor,
19785
+ phrases: []
19786
+ };
19787
+ if (klass) row.klass = klass;
19788
+ rows.push(row);
19789
+ for (var k = 0; k < str.length; k++) {
19790
+ var thisWord = str[k];
19791
+ var font = thisWord.font ? thisWord.font : getTextSize.attr(defFont, klass).font;
19792
+ var phrase = {
19793
+ content: thisWord.text
19794
+ };
19795
+ if (font) phrase.attrs = {
19796
+ "font-family": getTextSize.getFamily(font.face),
19797
+ "font-size": font.size,
19798
+ "font-weight": font.weight,
19799
+ "font-style": font.style,
19800
+ "font-decoration": font.decoration
19801
+ };
19802
+ //if (thisWord.text) {
19803
+ row.phrases.push(phrase);
19804
+ var size = getTextSize.calc(thisWord.text, font, klass);
19805
+ largestY = Math.max(largestY, size.height);
19806
+ if (thisWord.text[thisWord.text.length - 1] === ' ') {
19807
+ gap = space.width;
19808
+ }
19809
+ }
19810
+ rows.push({
19811
+ move: largestY
19812
+ });
19813
+ }
19814
+ }
19815
+ module.exports = richText;
19816
+
19817
+ /***/ }),
19818
+
19577
19819
  /***/ "./src/write/creation/elements/separator.js":
19578
19820
  /*!**************************************************!*\
19579
19821
  !*** ./src/write/creation/elements/separator.js ***!
@@ -19998,7 +20240,8 @@ module.exports = TieElem;
19998
20240
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
19999
20241
 
20000
20242
  var addTextIf = __webpack_require__(/*! ../add-text-if */ "./src/write/creation/add-text-if.js");
20001
- function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, getTextSize) {
20243
+ var richText = __webpack_require__(/*! ./rich-text */ "./src/write/creation/elements/rich-text.js");
20244
+ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) {
20002
20245
  this.rows = [];
20003
20246
  if (metaText.header && isPrint) {
20004
20247
  // Note: whether there is a header or not doesn't change any other positioning, so this doesn't change the Y-coordinate.
@@ -20043,31 +20286,23 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
20043
20286
  var tAnchor = formatting.titleleft ? 'start' : 'middle';
20044
20287
  var tLeft = formatting.titleleft ? paddingLeft : paddingLeft + width / 2;
20045
20288
  if (metaText.title) {
20046
- addTextIf(this.rows, {
20047
- marginLeft: tLeft,
20048
- text: metaText.title,
20049
- font: 'titlefont',
20050
- klass: 'title meta-top',
20289
+ var klass = shouldAddClasses ? 'abcjs-title' : '';
20290
+ richText(this.rows, metaText.title, "titlefont", klass, 'title', tLeft, {
20051
20291
  marginTop: spacing.title,
20052
20292
  anchor: tAnchor,
20053
20293
  absElemType: "title",
20054
- info: metaTextInfo.title,
20055
- name: "title"
20294
+ info: metaTextInfo.title
20056
20295
  }, getTextSize);
20057
20296
  }
20058
20297
  if (lines.length) {
20059
20298
  var index = 0;
20060
20299
  while (index < lines.length && lines[index].subtitle) {
20061
- addTextIf(this.rows, {
20062
- marginLeft: tLeft,
20063
- text: lines[index].subtitle.text,
20064
- font: 'subtitlefont',
20065
- klass: 'text meta-top subtitle',
20300
+ var klass = shouldAddClasses ? 'abcjs-text abcjs-subtitle' : '';
20301
+ richText(this.rows, lines[index].subtitle.text, "subtitlefont", klass, 'subtitle', tLeft, {
20066
20302
  marginTop: spacing.subtitle,
20067
20303
  anchor: tAnchor,
20068
20304
  absElemType: "subtitle",
20069
- info: lines[index].subtitle,
20070
- name: "subtitle"
20305
+ info: lines[index].subtitle
20071
20306
  }, getTextSize);
20072
20307
  index++;
20073
20308
  }
@@ -20078,54 +20313,68 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
20078
20313
  });
20079
20314
  if (metaText.rhythm && metaText.rhythm.length > 0) {
20080
20315
  var noMove = !!(metaText.composer || metaText.origin);
20316
+ var klass = shouldAddClasses ? 'abcjs-rhythm' : '';
20081
20317
  addTextIf(this.rows, {
20082
20318
  marginLeft: paddingLeft,
20083
20319
  text: metaText.rhythm,
20084
20320
  font: 'infofont',
20085
- klass: 'meta-top rhythm',
20321
+ klass: klass,
20086
20322
  absElemType: "rhythm",
20087
20323
  noMove: noMove,
20088
20324
  info: metaTextInfo.rhythm,
20089
20325
  name: "rhythm"
20090
20326
  }, getTextSize);
20091
20327
  }
20092
- var composerLine = "";
20093
- if (metaText.composer) composerLine += metaText.composer;
20094
- if (metaText.origin) composerLine += ' (' + metaText.origin + ')';
20095
- if (composerLine.length > 0) {
20096
- addTextIf(this.rows, {
20097
- marginLeft: paddingLeft + width,
20098
- text: composerLine,
20099
- font: 'composerfont',
20100
- klass: 'meta-top composer',
20328
+ var hasSimpleComposerLine = true;
20329
+ if (metaText.composer && typeof metaText.composer !== 'string') hasSimpleComposerLine = false;
20330
+ if (metaText.origin && typeof metaText.origin !== 'string') hasSimpleComposerLine = false;
20331
+ var composerLine = metaText.composer ? metaText.composer : '';
20332
+ if (metaText.origin) {
20333
+ if (typeof composerLine === 'string' && typeof metaText.origin === 'string') composerLine += ' (' + metaText.origin + ')';else if (typeof composerLine === 'string' && typeof metaText.origin !== 'string') {
20334
+ composerLine = [{
20335
+ text: composerLine
20336
+ }];
20337
+ composerLine.push({
20338
+ text: " ("
20339
+ });
20340
+ composerLine = composerLine.concat(metaText.origin);
20341
+ composerLine.push({
20342
+ text: ")"
20343
+ });
20344
+ } else {
20345
+ composerLine.push({
20346
+ text: " ("
20347
+ });
20348
+ composerLine = composerLine.concat(metaText.origin);
20349
+ composerLine.push({
20350
+ text: ")"
20351
+ });
20352
+ }
20353
+ }
20354
+ if (composerLine) {
20355
+ var klass = shouldAddClasses ? 'abcjs-composer' : '';
20356
+ richText(this.rows, composerLine, 'composerfont', klass, "composer", paddingLeft + width, {
20101
20357
  anchor: "end",
20102
20358
  absElemType: "composer",
20103
20359
  info: metaTextInfo.composer,
20104
- name: "composer"
20360
+ ingroup: true
20105
20361
  }, getTextSize);
20106
20362
  }
20107
20363
  }
20108
20364
  if (metaText.author && metaText.author.length > 0) {
20109
- addTextIf(this.rows, {
20110
- marginLeft: paddingLeft + width,
20111
- text: metaText.author,
20112
- font: 'composerfont',
20113
- klass: 'meta-top author',
20365
+ var klass = shouldAddClasses ? 'abcjs-author' : '';
20366
+ richText(this.rows, metaText.author, 'composerfont', klass, "author", paddingLeft + width, {
20114
20367
  anchor: "end",
20115
20368
  absElemType: "author",
20116
- info: metaTextInfo.author,
20117
- name: "author"
20369
+ info: metaTextInfo.author
20118
20370
  }, getTextSize);
20119
20371
  }
20120
20372
  if (metaText.partOrder && metaText.partOrder.length > 0) {
20121
- addTextIf(this.rows, {
20122
- marginLeft: paddingLeft,
20123
- text: metaText.partOrder,
20124
- font: 'partsfont',
20125
- klass: 'meta-top part-order',
20373
+ var klass = shouldAddClasses ? 'abcjs-part-order' : '';
20374
+ richText(this.rows, metaText.partOrder, 'partsfont', klass, "part-order", paddingLeft, {
20126
20375
  absElemType: "partOrder",
20127
20376
  info: metaTextInfo.partOrder,
20128
- name: "part-order"
20377
+ anchor: 'start'
20129
20378
  }, getTextSize);
20130
20379
  }
20131
20380
  }
@@ -20671,7 +20920,7 @@ var glyphs = {
20671
20920
  h: 7.515
20672
20921
  },
20673
20922
  ',': {
20674
- d: [['M', 1.32, -3.36], ['c', 0.57, -0.15, 1.17, 0.03, 1.59, 0.45], ['c', 0.45, 0.45, 0.60, 0.96, 0.51, 1.89], ['c', -0.09, 1.23, -0.42, 2.46, -0.99, 3.93], ['c', -0.30, 0.72, -0.72, 1.62, -0.78, 1.68], ['c', -0.18, 0.21, -0.51, 0.18, -0.66, -0.06], ['c', -0.03, -0.06, -0.06, -0.15, -0.06, -0.18], ['c', 0.00, -0.06, 0.12, -0.33, 0.24, -0.63], ['c', 0.84, -1.80, 1.02, -2.61, 0.69, -3.24], ['c', -0.12, -0.24, -0.27, -0.36, -0.75, -0.60], ['c', -0.36, -0.15, -0.42, -0.21, -0.60, -0.39], ['c', -0.69, -0.69, -0.69, -1.71, 0.00, -2.40], ['c', 0.21, -0.21, 0.51, -0.39, 0.81, -0.45], ['z']],
20923
+ d: [['M', 1.85, -3.36], ['c', 0.57, -0.15, 1.17, 0.03, 1.59, 0.45], ['c', 0.45, 0.45, 0.60, 0.96, 0.51, 1.89], ['c', -0.09, 1.23, -0.42, 2.46, -0.99, 3.93], ['c', -0.30, 0.72, -0.72, 1.62, -0.78, 1.68], ['c', -0.18, 0.21, -0.51, 0.18, -0.66, -0.06], ['c', -0.03, -0.06, -0.06, -0.15, -0.06, -0.18], ['c', 0.00, -0.06, 0.12, -0.33, 0.24, -0.63], ['c', 0.84, -1.80, 1.02, -2.61, 0.69, -3.24], ['c', -0.12, -0.24, -0.27, -0.36, -0.75, -0.60], ['c', -0.36, -0.15, -0.42, -0.21, -0.60, -0.39], ['c', -0.69, -0.69, -0.69, -1.71, 0.00, -2.40], ['c', 0.21, -0.21, 0.51, -0.39, 0.81, -0.45], ['z']],
20675
20924
  w: 3.452,
20676
20925
  h: 8.143
20677
20926
  },
@@ -20940,7 +21189,10 @@ function drawAbsolute(renderer, params, bartop, selectables, staffPos) {
20940
21189
  drawTempo(renderer, child);
20941
21190
  break;
20942
21191
  default:
20943
- drawRelativeElement(renderer, child, bartop);
21192
+ var el = drawRelativeElement(renderer, child, bartop);
21193
+ if (child.type === "symbol" && child.c && child.c.indexOf('notehead') >= 0) {
21194
+ el.setAttribute('class', 'abcjs-notehead');
21195
+ }
20944
21196
  }
20945
21197
  }
20946
21198
  var klass = params.type;
@@ -21243,7 +21495,9 @@ var spacing = __webpack_require__(/*! ../helpers/spacing */ "./src/write/helpers
21243
21495
  var Selectables = __webpack_require__(/*! ./selectables */ "./src/write/draw/selectables.js");
21244
21496
  function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, selectTypes, tuneNumber, lineOffset) {
21245
21497
  var selectables = new Selectables(renderer.paper, selectTypes, tuneNumber);
21246
- renderer.paper.openGroup();
21498
+ var groupClasses = {};
21499
+ if (classes.shouldAddClasses) groupClasses.klass = "abcjs-meta-top";
21500
+ renderer.paper.openGroup(groupClasses);
21247
21501
  renderer.moveY(renderer.padding.top);
21248
21502
  nonMusic(renderer, abcTune.topText, selectables);
21249
21503
  renderer.paper.closeGroup();
@@ -21253,7 +21507,8 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
21253
21507
  classes.incrLine();
21254
21508
  var abcLine = abcTune.lines[line];
21255
21509
  if (abcLine.staff) {
21256
- renderer.paper.openGroup();
21510
+ if (classes.shouldAddClasses) groupClasses.klass = "abcjs-staff l" + classes.lineNumber;
21511
+ renderer.paper.openGroup(groupClasses);
21257
21512
  if (abcLine.vskip) {
21258
21513
  renderer.moveY(abcLine.vskip);
21259
21514
  }
@@ -21263,14 +21518,16 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
21263
21518
  staffgroups.push(staffgroup);
21264
21519
  renderer.paper.closeGroup();
21265
21520
  } else if (abcLine.nonMusic) {
21266
- renderer.paper.openGroup();
21521
+ if (classes.shouldAddClasses) groupClasses.klass = "abcjs-non-music";
21522
+ renderer.paper.openGroup(groupClasses);
21267
21523
  nonMusic(renderer, abcLine.nonMusic, selectables);
21268
21524
  renderer.paper.closeGroup();
21269
21525
  }
21270
21526
  }
21271
21527
  classes.reset();
21272
21528
  if (abcTune.bottomText && abcTune.bottomText.rows && abcTune.bottomText.rows.length > 0) {
21273
- renderer.paper.openGroup();
21529
+ if (classes.shouldAddClasses) groupClasses.klass = "abcjs-meta-bottom";
21530
+ renderer.paper.openGroup(groupClasses);
21274
21531
  renderer.moveY(24); // TODO-PER: Empirically discovered. What variable should this be?
21275
21532
  nonMusic(renderer, abcTune.bottomText, selectables);
21276
21533
  renderer.paper.closeGroup();
@@ -21554,12 +21811,14 @@ function nonMusic(renderer, obj, selectables) {
21554
21811
  renderer.absolutemoveY(row.absmove);
21555
21812
  } else if (row.move) {
21556
21813
  renderer.moveY(row.move);
21557
- } else if (row.text) {
21814
+ } else if (row.text || row.phrases) {
21558
21815
  var x = row.left ? row.left : 0;
21559
21816
  var el = renderText(renderer, {
21560
21817
  x: x,
21561
21818
  y: renderer.y,
21562
21819
  text: row.text,
21820
+ phrases: row.phrases,
21821
+ 'dominant-baseline': row['dominant-baseline'],
21563
21822
  type: row.font,
21564
21823
  klass: row.klass,
21565
21824
  name: row.name,
@@ -21841,7 +22100,7 @@ function drawRelativeElement(renderer, params, bartop) {
21841
22100
  case "tabNumber":
21842
22101
  var hAnchor = "middle";
21843
22102
  var tabFont = "tabnumberfont";
21844
- var tabClass = 'tab-number';
22103
+ var tabClass = 'abcjs-tab-number';
21845
22104
  if (params.isGrace) {
21846
22105
  tabFont = "tabgracefont";
21847
22106
  y += 2.5;
@@ -22548,7 +22807,6 @@ function drawTempo(renderer, params) {
22548
22807
  klass: 'abcjs-tempo',
22549
22808
  anchor: "start",
22550
22809
  noClass: true,
22551
- "dominant-baseline": "ideographic",
22552
22810
  name: "pre"
22553
22811
  }, true);
22554
22812
  size = renderer.controller.getTextSize.calc(params.tempo.preString, 'tempofont', 'tempo', text);
@@ -22608,6 +22866,13 @@ module.exports = drawTempo;
22608
22866
  var roundNumber = __webpack_require__(/*! ./round-number */ "./src/write/draw/round-number.js");
22609
22867
  function renderText(renderer, params, alreadyInGroup) {
22610
22868
  var y = params.y;
22869
+
22870
+ // TODO-PER: Probably need to merge the regular text and rich text better. At the least, rich text loses the font box.
22871
+ if (params.phrases) {
22872
+ //richTextLine = function (phrases, x, y, klass, anchor, target)
22873
+ var elem = renderer.paper.richTextLine(params.phrases, params.x, params.y, params.klass, params.anchor);
22874
+ return elem;
22875
+ }
22611
22876
  if (params.lane) {
22612
22877
  var laneMargin = params.dim.font.size * 0.25;
22613
22878
  y += (params.dim.font.size + laneMargin) * params.lane;
@@ -22618,6 +22883,7 @@ function renderText(renderer, params, alreadyInGroup) {
22618
22883
  hash.attr["class"] = params.klass;
22619
22884
  } else hash = renderer.controller.getFontAndAttr.calc(params.type, params.klass);
22620
22885
  if (params.anchor) hash.attr["text-anchor"] = params.anchor;
22886
+ if (params['dominant-baseline']) hash.attr["dominant-baseline"] = params['dominant-baseline'];
22621
22887
  hash.attr.x = params.x;
22622
22888
  hash.attr.y = y;
22623
22889
  if (!params.centerVertically) hash.attr.y += hash.font.size;
@@ -23036,6 +23302,7 @@ var EngraverController = function EngraverController(paper, params) {
23036
23302
  this.renderer.setPaddingOverride(params);
23037
23303
  if (params.showDebug) this.renderer.showDebug = params.showDebug;
23038
23304
  if (params.jazzchords) this.jazzchords = params.jazzchords;
23305
+ if (params.accentAbove) this.accentAbove = params.accentAbove;
23039
23306
  if (params.germanAlphabet) this.germanAlphabet = params.germanAlphabet;
23040
23307
  if (params.lineThickness) this.lineThickness = params.lineThickness;
23041
23308
  this.renderer.controller = this; // TODO-GD needed for highlighting
@@ -23087,6 +23354,7 @@ EngraverController.prototype.getMeasureWidths = function (abcTune) {
23087
23354
  this.reset();
23088
23355
  this.getFontAndAttr = new GetFontAndAttr(abcTune.formatting, this.classes);
23089
23356
  this.getTextSize = new GetTextSize(this.getFontAndAttr, this.renderer.paper);
23357
+ var origJazzChords = this.jazzchords;
23090
23358
  this.setupTune(abcTune, 0);
23091
23359
  this.constructTuneElements(abcTune);
23092
23360
  // layout() sets the x-coordinate of the abcTune element here:
@@ -23130,11 +23398,13 @@ EngraverController.prototype.getMeasureWidths = function (abcTune) {
23130
23398
  //section.height += calcHeight(abcLine.staffGroup) * spacing.STEP;
23131
23399
  } else needNewSection = true;
23132
23400
  }
23401
+ this.jazzchords = origJazzChords;
23133
23402
  return ret;
23134
23403
  };
23135
23404
  EngraverController.prototype.setupTune = function (abcTune, tuneNumber) {
23136
23405
  this.classes.reset();
23137
23406
  if (abcTune.formatting.jazzchords !== undefined) this.jazzchords = abcTune.formatting.jazzchords;
23407
+ if (abcTune.formatting.accentAbove !== undefined) this.accentAbove = abcTune.formatting.accentAbove;
23138
23408
  this.renderer.newTune(abcTune);
23139
23409
  this.engraver = new AbstractEngraver(this.getTextSize, tuneNumber, {
23140
23410
  bagpipes: abcTune.formatting.bagpipes,
@@ -23144,6 +23414,7 @@ EngraverController.prototype.setupTune = function (abcTune, tuneNumber) {
23144
23414
  percmap: abcTune.formatting.percmap,
23145
23415
  initialClef: this.initialClef,
23146
23416
  jazzchords: this.jazzchords,
23417
+ accentAbove: this.accentAbove,
23147
23418
  germanAlphabet: this.germanAlphabet
23148
23419
  });
23149
23420
  this.engraver.setStemHeight(this.renderer.spacing.stemHeight);
@@ -23162,7 +23433,7 @@ EngraverController.prototype.setupTune = function (abcTune, tuneNumber) {
23162
23433
  return scale;
23163
23434
  };
23164
23435
  EngraverController.prototype.constructTuneElements = function (abcTune) {
23165
- abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize);
23436
+ abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.classes.shouldAddClasses, this.getTextSize);
23166
23437
 
23167
23438
  // Generate the raw staff line data
23168
23439
  var i;
@@ -23189,20 +23460,49 @@ EngraverController.prototype.constructTuneElements = function (abcTune) {
23189
23460
  abcLine.nonMusic = new Separator(abcLine.separator.spaceAbove, abcLine.separator.lineLength, abcLine.separator.spaceBelow);
23190
23461
  }
23191
23462
  }
23192
- abcTune.bottomText = new BottomText(abcTune.metaText, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize);
23463
+ abcTune.bottomText = new BottomText(abcTune.metaText, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.classes.shouldAddClasses, this.getTextSize);
23193
23464
  };
23194
23465
  EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOffset) {
23466
+ var origJazzChords = this.jazzchords;
23195
23467
  var scale = this.setupTune(abcTune, tuneNumber);
23196
23468
 
23197
23469
  // Create all of the element objects that will appear on the page.
23198
23470
  this.constructTuneElements(abcTune);
23199
23471
 
23472
+ //Set the top text now that we know the width
23473
+
23200
23474
  // Do all the positioning, both horizontally and vertically
23201
23475
  var maxWidth = layout(this.renderer, abcTune, this.width, this.space, this.expandToWidest);
23202
23476
 
23203
23477
  //Set the top text now that we know the width
23204
23478
  if (this.expandToWidest && maxWidth > this.width + 1) {
23205
- abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, maxWidth, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize);
23479
+ abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, maxWidth, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.classes.shouldAddClasses, this.getTextSize);
23480
+ if (abcTune.lines && abcTune.lines.length > 0) {
23481
+ var nlines = abcTune.lines.length;
23482
+ for (var i = 0; i < nlines; ++i) {
23483
+ var entry = abcTune.lines[i];
23484
+ if (entry.nonMusic) {
23485
+ if (entry.nonMusic.rows && entry.nonMusic.rows.length > 0) {
23486
+ var nRows = entry.nonMusic.rows.length;
23487
+ for (var j = 0; j < nRows; ++j) {
23488
+ var thisRow = entry.nonMusic.rows[j];
23489
+ // Recenter the element if it's a subtitle or centered text
23490
+ if (thisRow.left) {
23491
+ if (entry.subtitle) {
23492
+ thisRow.left = maxWidth / 2 + this.renderer.padding.left;
23493
+ } else {
23494
+ if (entry.text && entry.text.length > 0) {
23495
+ if (entry.text[0].center) {
23496
+ thisRow.left = maxWidth / 2 + this.renderer.padding.left;
23497
+ }
23498
+ }
23499
+ }
23500
+ }
23501
+ }
23502
+ }
23503
+ }
23504
+ }
23505
+ }
23206
23506
  }
23207
23507
 
23208
23508
  // Deal with tablature for staff
@@ -23221,6 +23521,7 @@ EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOf
23221
23521
  this.svgs = [this.renderer.paper.svg];
23222
23522
  }
23223
23523
  setupSelection(this, this.svgs);
23524
+ this.jazzchords = origJazzChords;
23224
23525
  };
23225
23526
  function splitSvgIntoLines(renderer, output, title, responsive) {
23226
23527
  // Each line is a top level <g> in the svg. To split it into separate
@@ -23368,7 +23669,7 @@ Classes.prototype.generate = function (c) {
23368
23669
  if (!this.shouldAddClasses) return "";
23369
23670
  var ret = [];
23370
23671
  if (c && c.length > 0) ret.push(c);
23371
- if (c === "tab-number")
23672
+ if (c === "abcjs-tab-number")
23372
23673
  // TODO-PER-HACK! straighten out the tablature
23373
23674
  return ret.join(' ');
23374
23675
  if (c === "text instrument-name") return "abcjs-text abcjs-instrument-name";
@@ -23409,6 +23710,12 @@ GetFontAndAttr.prototype.updateFonts = function (fontOverrides) {
23409
23710
  if (fontOverrides.annotationfont) this.formatting.annotationfont = fontOverrides.annotationfont;
23410
23711
  if (fontOverrides.vocalfont) this.formatting.vocalfont = fontOverrides.vocalfont;
23411
23712
  };
23713
+ GetFontAndAttr.prototype.getFamily = function (type) {
23714
+ if (type[0] === '"' && type[type.length - 1] === '"') {
23715
+ return type.substring(1, type.length - 1);
23716
+ }
23717
+ return type;
23718
+ };
23412
23719
  GetFontAndAttr.prototype.calc = function (type, klass) {
23413
23720
  var font;
23414
23721
  if (typeof type === 'string') {
@@ -23441,7 +23748,7 @@ GetFontAndAttr.prototype.calc = function (type, klass) {
23441
23748
  var attr = {
23442
23749
  "font-size": font.size,
23443
23750
  'font-style': font.style,
23444
- "font-family": font.face,
23751
+ "font-family": this.getFamily(font.face),
23445
23752
  'font-weight': font.weight,
23446
23753
  'text-decoration': font.decoration,
23447
23754
  'class': this.classes.generate(klass)
@@ -23471,6 +23778,12 @@ GetTextSize.prototype.updateFonts = function (fontOverrides) {
23471
23778
  GetTextSize.prototype.attr = function (type, klass) {
23472
23779
  return this.getFontAndAttr.calc(type, klass);
23473
23780
  };
23781
+ GetTextSize.prototype.getFamily = function (type) {
23782
+ if (type[0] === '"' && type[type.length - 1] === '"') {
23783
+ return type.substring(1, type.length - 1);
23784
+ }
23785
+ return type;
23786
+ };
23474
23787
  GetTextSize.prototype.calc = function (text, type, klass, el) {
23475
23788
  var hash;
23476
23789
  // This can be passed in either a string or a font. If it is a string it names one of the standard fonts.
@@ -23486,7 +23799,7 @@ GetTextSize.prototype.calc = function (text, type, klass, el) {
23486
23799
  attr: {
23487
23800
  "font-size": type.size,
23488
23801
  "font-style": type.style,
23489
- "font-family": type.face,
23802
+ "font-family": this.getFamily(type.face),
23490
23803
  "font-weight": type.weight,
23491
23804
  "text-decoration": type.decoration,
23492
23805
  "class": this.getFontAndAttr.classes.generate(klass)
@@ -25484,6 +25797,28 @@ Svg.prototype.text = function (text, attr, target) {
25484
25797
  if (target) target.appendChild(el);else this.append(el);
25485
25798
  return el;
25486
25799
  };
25800
+ Svg.prototype.richTextLine = function (phrases, x, y, klass, anchor, target) {
25801
+ var el = document.createElementNS(svgNS, 'text');
25802
+ el.setAttribute("stroke", "none");
25803
+ el.setAttribute("class", klass);
25804
+ el.setAttribute("x", x);
25805
+ el.setAttribute("y", y);
25806
+ el.setAttribute("text-anchor", anchor);
25807
+ el.setAttribute("dominant-baseline", "middle");
25808
+ for (var i = 0; i < phrases.length; i++) {
25809
+ var phrase = phrases[i];
25810
+ var tspan = document.createElementNS(svgNS, 'tspan');
25811
+ var attrs = Object.keys(phrase.attrs);
25812
+ for (var j = 0; j < attrs.length; j++) {
25813
+ var value = phrase.attrs[attrs[j]];
25814
+ if (value !== '') tspan.setAttribute(attrs[j], value);
25815
+ }
25816
+ tspan.textContent = phrase.content;
25817
+ el.appendChild(tspan);
25818
+ }
25819
+ if (target) target.appendChild(el);else this.append(el);
25820
+ return el;
25821
+ };
25487
25822
  Svg.prototype.guessWidth = function (text, attr) {
25488
25823
  var svg = this.createDummySvg();
25489
25824
  var el = this.text(text, attr, svg);
@@ -25635,7 +25970,7 @@ module.exports = Svg;
25635
25970
  \********************/
25636
25971
  /***/ (function(module) {
25637
25972
 
25638
- var version = '6.2.3';
25973
+ var version = '6.3.0';
25639
25974
  module.exports = version;
25640
25975
 
25641
25976
  /***/ })