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
@@ -37,12 +37,24 @@ function buildTabName(self, dest) {
37
37
  var controller = self.renderer.controller;
38
38
  var textSize = controller.getTextSize;
39
39
  var tabName = stringSemantics.tabInfos(self.plugin);
40
- var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname');
41
- dest.tabNameInfos = {
42
- textSize: size,
43
- name: tabName
44
- };
45
- return size.height;
40
+ var suppress = stringSemantics.suppress(self.plugin);
41
+ var doDraw = true;
42
+
43
+ if (suppress){
44
+ doDraw = false
45
+ }
46
+
47
+
48
+ if (doDraw){
49
+ var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname');
50
+ dest.tabNameInfos = {
51
+ textSize: {height:size.height,width:size.width},
52
+ name: tabName
53
+ };
54
+ return size.height;
55
+ }
56
+ return 0
57
+
46
58
  }
47
59
 
48
60
  /**
@@ -230,8 +242,10 @@ TabRenderer.prototype.doLayout = function () {
230
242
  if (ii > 0) tabVoice.duplicate = true;
231
243
  var nameHeight = buildTabName(this, tabVoice) / spacing.STEP;
232
244
  nameHeight = Math.max(nameHeight, 1) // If there is no label for the tab line, then there needs to be a little padding
233
- staffGroup.staffs[this.staffIndex].top += nameHeight;
234
- staffGroup.height += nameHeight * spacing.STEP;
245
+ // This was pushing down the top staff by the tab label height
246
+ //staffGroup.staffs[this.staffIndex].top += nameHeight;
247
+ staffGroup.staffs[this.staffIndex].top += 1;
248
+ staffGroup.height += nameHeight;
235
249
  tabVoice.staff = staffGroupInfos;
236
250
  var tabVoiceIndex = voices.length
237
251
  voices.splice(voices.length, 0, tabVoice);
@@ -242,5 +256,4 @@ TabRenderer.prototype.doLayout = function () {
242
256
  linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
243
257
  };
244
258
 
245
-
246
259
  module.exports = TabRenderer;
@@ -51,18 +51,18 @@
51
51
  var parseCommon = require('../parse/abc_common');
52
52
  var JSONSchema = require('./jsonschema-b4');
53
53
 
54
- var { legalAccents } = require('../parse/abc_parse_settings');
55
-
56
- var ParserLint = function () {
57
- 'use strict';
58
- var decorationList = {
59
- type: 'array',
60
- optional: true,
61
- items: {
62
- type: 'string',
63
- Enum: legalAccents
64
- }
65
- };
54
+ var ParserLint = function() {
55
+ "use strict";
56
+ var decorationList = { type: 'array', optional: true, items: { type: 'string', Enum: [
57
+ "trill", "lowermordent", "uppermordent", "mordent", "pralltriller", "accent",
58
+ "fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge",
59
+ "open", "thumb", "snap", "turn", "roll", "irishroll", "breath", "shortphrase", "mediumphrase", "longphrase",
60
+ "segno", "coda", "D.S.", "D.C.", "fine", "crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)",
61
+ "p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz", "repeatbar", "repeatbar2", "slide",
62
+ "upbow", "downbow", "staccato", "trem1", "trem2", "trem3", "trem4",
63
+ "/", "//", "///", "////", "turnx", "invertedturn", "invertedturnx", "arpeggio", "trill(", "trill)", "xstem",
64
+ "mark", "marcato", "umarcato", "D.C.alcoda", "D.C.alfine", "D.S.alcoda", "D.S.alfine", "editorial", "courtesy"
65
+ ] } };
66
66
 
67
67
  var tempoProperties = {
68
68
  duration: { type: "array", optional: true, output: "join", requires: [ 'bpm'], items: { type: "number"} },
@@ -427,6 +427,7 @@ var ParserLint = function () {
427
427
  var formattingProperties = {
428
428
  type:"object",
429
429
  properties: {
430
+ accentAbove: { type: "boolean", optional: true },
430
431
  alignbars: { type: "number", optional: true },
431
432
  aligncomposer: { type: "string", Enum: [ 'left', 'center','right' ], optional: true },
432
433
  annotationfont: fontType,
@@ -53,6 +53,7 @@ var AbstractEngraver = function (getTextSize, tuneNumber, options) {
53
53
  this.percmap = options.percmap;
54
54
  this.initialClef = options.initialClef
55
55
  this.jazzchords = !!options.jazzchords
56
+ this.accentAbove = !!options.accentAbove
56
57
  this.germanAlphabet = !!options.germanAlphabet
57
58
  this.reset();
58
59
  };
@@ -830,7 +831,7 @@ AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaf
830
831
  }
831
832
 
832
833
  if (elem.decoration) {
833
- this.decoration.createDecoration(voice, elem.decoration, abselem.top, (notehead) ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals);
834
+ this.decoration.createDecoration(voice, elem.decoration, abselem.top, (notehead) ? notehead.w : 0, abselem, roomtaken, dir, abselem.bottom, elem.positioning, this.hasVocals, this.accentAbove);
834
835
  }
835
836
 
836
837
  if (elem.barNumber) {
@@ -989,7 +990,7 @@ AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff)
989
990
  }
990
991
 
991
992
  if (elem.decoration) {
992
- this.decoration.createDecoration(voice, elem.decoration, 12, (thick) ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals);
993
+ this.decoration.createDecoration(voice, elem.decoration, 12, (thick) ? 3 : 1, abselem, 0, "down", 2, elem.positioning, this.hasVocals, this.accentAbove);
993
994
  }
994
995
 
995
996
  if (thick) {
@@ -6,97 +6,117 @@ var addChord = function (getTextSize, abselem, elem, roomTaken, roomTakenRight,
6
6
  for (var i = 0; i < elem.chord.length; i++) {
7
7
  var pos = elem.chord[i].position;
8
8
  var rel_position = elem.chord[i].rel_position;
9
- var chords = elem.chord[i].name.split("\n");
10
- for (var j = chords.length - 1; j >= 0; j--) { // parse these in opposite order because we place them from bottom to top.
11
- var chord = chords[j];
12
- var x = 0;
13
- var y;
14
- var font;
15
- var klass;
16
- if (pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position) {
17
- font = 'annotationfont';
18
- klass = "annotation";
19
- } else {
20
- font = 'gchordfont';
21
- klass = "chord";
22
- chord = translateChord(chord, jazzchords, germanAlphabet);
9
+ var isAnnotation = pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position
10
+ var font;
11
+ var klass;
12
+ if (isAnnotation) {
13
+ font = 'annotationfont';
14
+ klass = "abcjs-annotation";
15
+ } else {
16
+ font = 'gchordfont';
17
+ klass = "abcjs-chord";
18
+ }
19
+ var attr = getTextSize.attr(font, klass);
20
+
21
+ var name = elem.chord[i].name
22
+ var ret;
23
+ //console.log("chord",name)
24
+ if (typeof name === "string") {
25
+ ret = chordString(name, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet)
26
+ roomTaken = ret.roomTaken
27
+ roomTakenRight = ret.roomTakenRight
28
+ } else {
29
+ for (var j = 0; j < name.length; j++) {
30
+ ret = chordString(name[j].text, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet)
31
+ roomTaken = ret.roomTaken
32
+ roomTakenRight = ret.roomTakenRight
23
33
  }
24
- var attr = getTextSize.attr(font, klass);
25
- var dim = getTextSize.calc(chord, font, klass);
26
- var chordWidth = dim.width;
27
- var chordHeight = dim.height / spacing.STEP;
28
- switch (pos) {
29
- case "left":
30
- roomTaken += chordWidth + 7;
31
- x = -roomTaken; // TODO-PER: This is just a guess from trial and error
32
- y = elem.averagepitch;
33
- abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, {
34
- type: "text",
35
- height: chordHeight,
36
- dim: attr,
37
- position: "left"
38
- }));
39
- break;
40
- case "right":
41
- roomTakenRight += 4;
42
- x = roomTakenRight;// TODO-PER: This is just a guess from trial and error
43
- y = elem.averagepitch;
44
- abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, {
45
- type: "text",
46
- height: chordHeight,
47
- dim: attr,
48
- position: "right"
49
- }));
50
- break;
51
- case "below":
52
- // 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.
53
- abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
34
+ }
35
+ }
36
+ return { roomTaken: roomTaken, roomTakenRight: roomTakenRight };
37
+ };
38
+
39
+ function chordString(chordString, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet) {
40
+ var chords = chordString.split("\n");
41
+ for (var j = chords.length - 1; j >= 0; j--) { // parse these in opposite order because we place them from bottom to top.
42
+ var chord = chords[j];
43
+ var x = 0;
44
+ var y;
45
+ if (!isAnnotation)
46
+ chord = translateChord(chord, jazzchords, germanAlphabet);
47
+ var dim = getTextSize.calc(chord, font, klass);
48
+ var chordWidth = dim.width;
49
+ var chordHeight = dim.height / spacing.STEP;
50
+ switch (pos) {
51
+ case "left":
52
+ roomTaken += chordWidth + 7;
53
+ x = -roomTaken; // TODO-PER: This is just a guess from trial and error
54
+ y = elem.averagepitch;
55
+ abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, {
56
+ type: "text",
57
+ height: chordHeight,
58
+ dim: attr,
59
+ position: "left"
60
+ }));
61
+ break;
62
+ case "right":
63
+ roomTakenRight += 4;
64
+ x = roomTakenRight;// TODO-PER: This is just a guess from trial and error
65
+ y = elem.averagepitch;
66
+ abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, {
67
+ type: "text",
68
+ height: chordHeight,
69
+ dim: attr,
70
+ position: "right"
71
+ }));
72
+ break;
73
+ case "below":
74
+ // 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.
75
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
76
+ type: "text",
77
+ position: "below",
78
+ height: chordHeight,
79
+ dim: attr,
80
+ realWidth: chordWidth
81
+ }));
82
+ break;
83
+ case "above":
84
+ // 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.
85
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
86
+ type: "text",
87
+ position: "above",
88
+ height: chordHeight,
89
+ dim: attr,
90
+ realWidth: chordWidth
91
+ }));
92
+ break;
93
+ default:
94
+ if (rel_position) {
95
+ var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps
96
+ abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, {
97
+ position: "relative",
54
98
  type: "text",
55
- position: "below",
56
99
  height: chordHeight,
57
- dim: attr,
58
- realWidth: chordWidth
100
+ dim: attr
59
101
  }));
60
- break;
61
- case "above":
102
+ } else {
62
103
  // 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.
63
- abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
64
- type: "text",
65
- position: "above",
66
- height: chordHeight,
67
- dim: attr,
68
- realWidth: chordWidth
69
- }));
70
- break;
71
- default:
72
- if (rel_position) {
73
- var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps
74
- abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, {
75
- position: "relative",
76
- type: "text",
104
+ var pos2 = 'above';
105
+ if (elem.positioning && elem.positioning.chordPosition)
106
+ pos2 = elem.positioning.chordPosition;
107
+
108
+ if (pos2 !== 'hidden') {
109
+ abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, {
110
+ type: "chord",
111
+ position: pos2,
77
112
  height: chordHeight,
78
- dim: attr
113
+ dim: attr,
114
+ realWidth: chordWidth
79
115
  }));
80
- } else {
81
- // 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.
82
- var pos2 = 'above';
83
- if (elem.positioning && elem.positioning.chordPosition)
84
- pos2 = elem.positioning.chordPosition;
85
-
86
- if (pos2 !== 'hidden') {
87
- abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, {
88
- type: "chord",
89
- position: pos2,
90
- height: chordHeight,
91
- dim: attr,
92
- realWidth: chordWidth
93
- }));
94
- }
95
116
  }
96
- }
117
+ }
97
118
  }
98
119
  }
99
120
  return { roomTaken: roomTaken, roomTakenRight: roomTakenRight };
100
- };
101
-
121
+ }
102
122
  module.exports = addChord;
@@ -8,10 +8,10 @@ function addTextIf(rows, params, getTextSize) {
8
8
 
9
9
  if (params.marginTop)
10
10
  rows.push({ move: params.marginTop });
11
- var attr = { left: params.marginLeft, text: params.text, font: params.font, anchor: params.anchor, startChar: params.info.startChar, endChar: params.info.endChar };
11
+ var attr = { left: params.marginLeft, text: params.text, font: params.font, anchor: params.anchor, startChar: params.info.startChar, endChar: params.info.endChar, 'dominant-baseline': params['dominant-baseline'] };
12
12
  if (params.absElemType)
13
13
  attr.absElemType = params.absElemType;
14
- if (!params.inGroup)
14
+ if (!params.inGroup && params.klass)
15
15
  attr.klass = params.klass;
16
16
  if (params.name)
17
17
  attr.name = params.name;
@@ -14,10 +14,10 @@ var Decoration = function Decoration() {
14
14
  this.minBottom = 0;
15
15
  };
16
16
 
17
- var closeDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch) {
17
+ var closeDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove) {
18
18
  var yPos;
19
19
  for (var i = 0; i < decoration.length; i++) {
20
- if (decoration[i] === "staccato" || decoration[i] === "tenuto" || decoration[i] === "accent") {
20
+ if (decoration[i] === "staccato" || decoration[i] === "tenuto" || (decoration[i] === "accent" && !accentAbove)) {
21
21
  var symbol = "scripts." + decoration[i];
22
22
  if (decoration[i] === "accent") symbol = "scripts.sforzato";
23
23
  if (yPos === undefined)
@@ -123,7 +123,7 @@ var compoundDecoration = function (decoration, pitch, width, abselem, dir) {
123
123
  }
124
124
  };
125
125
 
126
- var stackedDecoration = function (decoration, width, abselem, yPos, positioning, minTop, minBottom) {
126
+ var stackedDecoration = function (decoration, width, abselem, yPos, positioning, minTop, minBottom, accentAbove) {
127
127
  function incrementPlacement(placement, height) {
128
128
  if (placement === 'above')
129
129
  yPos.above += height;
@@ -263,6 +263,12 @@ var stackedDecoration = function (decoration, width, abselem, yPos, positioning,
263
263
  case "mark":
264
264
  abselem.klass = "mark";
265
265
  break;
266
+ case "accent":
267
+ if (accentAbove) {
268
+ symbolDecoration("scripts.sforzato", positioning);
269
+ hasOne = true;
270
+ }
271
+ break;
266
272
  }
267
273
  }
268
274
  return hasOne;
@@ -336,7 +342,7 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
336
342
  }
337
343
  };
338
344
 
339
- Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals) {
345
+ Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals, accentAbove) {
340
346
  if (!positioning)
341
347
  positioning = { ornamentPosition: 'above', volumePosition: hasVocals ? 'above' : 'below', dynamicPosition: hasVocals ? 'above' : 'below' };
342
348
  // These decorations don't affect the placement of other decorations
@@ -345,14 +351,14 @@ Decoration.prototype.createDecoration = function (voice, decoration, pitch, widt
345
351
  compoundDecoration(decoration, pitch, width, abselem, dir);
346
352
 
347
353
  // treat staccato, accent, and tenuto first (may need to shift other markers)
348
- var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch);
354
+ var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove);
349
355
  // yPos is an object containing 'above' and 'below'. That is the placement of the next symbol on either side.
350
356
 
351
357
  yPos.above = Math.max(yPos.above, this.minTop);
352
- var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom);
353
- if (hasOne) {
358
+ var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom, accentAbove);
359
+ //if (hasOne) {
354
360
  // abselem.top = Math.max(yPos.above + 3, abselem.top); // TODO-PER: Not sure why we need this fudge factor.
355
- }
361
+ //}
356
362
  leftDecoration(decoration, abselem, roomtaken);
357
363
  };
358
364
 
@@ -1,68 +1,83 @@
1
1
  const addTextIf = require("../add-text-if");
2
+ const richText = require("./rich-text");
2
3
 
3
- function BottomText(metaText, width, isPrint, paddingLeft, spacing, getTextSize) {
4
+ function BottomText(metaText, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) {
4
5
  this.rows = [];
5
6
  if (metaText.unalignedWords && metaText.unalignedWords.length > 0)
6
- this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, getTextSize);
7
- this.extraText(metaText, paddingLeft, spacing, getTextSize);
7
+ this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, shouldAddClasses, getTextSize);
8
+ this.extraText(metaText, paddingLeft, spacing, shouldAddClasses, getTextSize);
8
9
  if (metaText.footer && isPrint)
9
10
  this.footer(metaText.footer, width, paddingLeft, getTextSize);
10
11
  }
11
12
 
12
- BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spacing, getTextSize) {
13
- var klass = 'meta-bottom unaligned-words';
13
+ BottomText.prototype.unalignedWords = function (unalignedWords, marginLeft, spacing, shouldAddClasses, getTextSize) {
14
+ var klass = shouldAddClasses ? 'abcjs-unaligned-words' : ''
14
15
  var defFont = 'wordsfont';
15
- this.rows.push({ startGroup: "unalignedWords", klass: 'abcjs-meta-bottom abcjs-unaligned-words', name: "words" });
16
16
  var space = getTextSize.calc("i", defFont, klass);
17
-
17
+
18
18
  this.rows.push({ move: spacing.words });
19
+
20
+ addMultiLine(this.rows, '', unalignedWords, marginLeft, defFont, "unalignedWords", "unalignedWords", klass, "unalignedWords", spacing, shouldAddClasses, getTextSize)
21
+ this.rows.push({ move: space.height });
22
+ }
23
+
24
+ function addSingleLine(rows, preface, text, marginLeft, klass, shouldAddClasses, getTextSize) {
25
+ if (text) {
26
+ if (preface) {
27
+ if (typeof text === 'string')
28
+ text = preface + text
29
+ else
30
+ text = [{text: preface}].concat(text)
31
+ }
32
+ klass = shouldAddClasses ? 'abcjs-extra-text '+klass : ''
33
+ richText(rows, text, 'historyfont', klass, "description", marginLeft, {absElemType: "extraText", anchor: 'start'}, getTextSize)
34
+ }
35
+
36
+ }
19
37
 
20
- for (var j = 0; j < unalignedWords.length; j++) {
21
- if (unalignedWords[j] === '')
22
- this.rows.push({ move: space.height });
23
- else if (typeof unalignedWords[j] === 'string') {
24
- addTextIf(this.rows, { marginLeft: paddingLeft, text: unalignedWords[j], font: defFont, klass: klass, inGroup: true, name: "words" }, getTextSize);
38
+ function addMultiLine(rows, preface, content, marginLeft, defFont, absElemType, groupName, klass, name, spacing, shouldAddClasses, getTextSize) {
39
+ if (content) {
40
+ klass = shouldAddClasses ? 'abcjs-extra-text '+klass : ''
41
+ var size = getTextSize.calc("A", defFont, klass);
42
+ if (typeof content === 'string') {
43
+ if (preface)
44
+ content = preface + "\n" + content
45
+ addTextIf(rows, { marginLeft: marginLeft, text: content, font: defFont, absElemType: "extraText", name: name, 'dominant-baseline': 'middle', klass: klass }, getTextSize);
46
+ //rows.push({move: size.height*3/4})
25
47
  } else {
26
- var largestY = 0;
27
- var offsetX = 0;
28
- for (var k = 0; k < unalignedWords[j].length; k++) {
29
- var thisWord = unalignedWords[j][k];
30
- var font = (thisWord.font) ? thisWord.font : defFont;
31
- this.rows.push({
32
- left: paddingLeft + offsetX,
33
- text: thisWord.text,
34
- font: font,
35
- anchor: 'start'
36
- });
37
- var size = getTextSize.calc(thisWord.text, defFont, klass);
38
- largestY = Math.max(largestY, size.height);
39
- offsetX += size.width;
40
- // If the phrase ends in a space, then that is not counted in the width, so we need to add that in ourselves.
41
- if (thisWord.text[thisWord.text.length - 1] === ' ') {
42
- offsetX += space.width;
43
- }
48
+ rows.push({ startGroup: groupName, klass: klass, name: name });
49
+ rows.push({move: spacing.info})
50
+ if (preface) {
51
+ addTextIf(rows, { marginLeft: marginLeft, text: preface, font: defFont, absElemType: "extraText", name: name, 'dominant-baseline': 'middle' }, getTextSize);
52
+ rows.push({move: size.height*3/4})
44
53
  }
45
- this.rows.push({ move: largestY });
54
+
55
+ for (var j = 0; j < content.length; j++) {
56
+ richText(rows, content[j], defFont, '', name, marginLeft, {anchor: 'start'}, getTextSize)
57
+ // TODO-PER: Hack! the string and rich lines should have used up the same amount of space without this.
58
+ if (j < content.length-1 && typeof content[j] === 'string' && typeof content[j+1] !== 'string')
59
+ rows.push({move: size.height*3/4})
60
+ }
61
+ rows.push({ endGroup: groupName, absElemType: absElemType, startChar: -1, endChar: -1, name: name });
62
+ rows.push({move: size.height})
46
63
  }
47
64
  }
48
- this.rows.push({ move: space.height * 2 });
49
- this.rows.push({ endGroup: "unalignedWords", absElemType: "unalignedWords", startChar: -1, endChar: -1, name: "unalignedWords" });
50
65
  }
66
+ BottomText.prototype.extraText = function (metaText, marginLeft, spacing, shouldAddClasses, getTextSize) {
67
+ addSingleLine(this.rows, "Book: ", metaText.book, marginLeft, 'abcjs-book', shouldAddClasses, getTextSize)
68
+ addSingleLine(this.rows, "Source: ", metaText.source, marginLeft, 'abcjs-source', shouldAddClasses, getTextSize)
69
+ addSingleLine(this.rows, "Discography: ", metaText.discography, marginLeft, 'abcjs-discography', shouldAddClasses, getTextSize)
70
+
71
+ addMultiLine(this.rows, 'Notes:', metaText.notes, marginLeft, 'historyfont', "extraText", "notes", 'abcjs-notes', "description", spacing, shouldAddClasses, getTextSize)
72
+
73
+ addSingleLine(this.rows, "Transcription: ", metaText.transcription, marginLeft, 'abcjs-transcription', shouldAddClasses, getTextSize)
74
+
75
+ addMultiLine(this.rows, "History:", metaText.history, marginLeft, 'historyfont', "extraText", "history", 'abcjs-history', "description", spacing, shouldAddClasses, getTextSize)
76
+
77
+ addSingleLine(this.rows, "Copyright: ", metaText['abc-copyright'], marginLeft, 'abcjs-copyright', shouldAddClasses, getTextSize)
78
+ addSingleLine(this.rows, "Creator: ", metaText['abc-creator'], marginLeft, 'abcjs-creator', shouldAddClasses, getTextSize)
79
+ addSingleLine(this.rows, "Edited By: ", metaText['abc-edited-by'], marginLeft, 'abcjs-edited-by', shouldAddClasses, getTextSize)
51
80
 
52
- BottomText.prototype.extraText = function (metaText, marginLeft, spacing, getTextSize) {
53
- var extraText = "";
54
- if (metaText.book) extraText += "Book: " + metaText.book + "\n";
55
- if (metaText.source) extraText += "Source: " + metaText.source + "\n";
56
- if (metaText.discography) extraText += "Discography: " + metaText.discography + "\n";
57
- if (metaText.notes) extraText += "Notes: " + metaText.notes + "\n";
58
- if (metaText.transcription) extraText += "Transcription: " + metaText.transcription + "\n";
59
- if (metaText.history) extraText += "History: " + metaText.history + "\n";
60
- if (metaText['abc-copyright']) extraText += "Copyright: " + metaText['abc-copyright'] + "\n";
61
- if (metaText['abc-creator']) extraText += "Creator: " + metaText['abc-creator'] + "\n";
62
- if (metaText['abc-edited-by']) extraText += "Edited By: " + metaText['abc-edited-by'] + "\n";
63
- if (extraText.length > 0) {
64
- addTextIf(this.rows, { marginLeft: marginLeft, text: extraText, font: 'historyfont', klass: 'meta-bottom extra-text', marginTop: spacing.info, absElemType: "extraText", name: "description" }, getTextSize);
65
- }
66
81
  }
67
82
 
68
83
  BottomText.prototype.footer = function (footer, width, paddingLeft, getTextSize) {
@@ -0,0 +1,51 @@
1
+ const addTextIf = require("../add-text-if");
2
+
3
+ function richText(rows, str, defFont, klass, name, paddingLeft, attr, getTextSize) {
4
+ var space = getTextSize.calc("i", defFont, klass);
5
+ if (str === '') {
6
+ rows.push({ move: space.height });
7
+ } else {
8
+ if (typeof str === 'string') {
9
+ addTextIf(rows, { marginLeft: paddingLeft, text: str, font: defFont, klass: klass, marginTop: attr.marginTop, anchor: attr.anchor, absElemType: attr.absElemType, info: attr.info, name: name }, getTextSize);
10
+ return
11
+ }
12
+ if (attr.marginTop)
13
+ rows.push({move: attr.marginTop})
14
+
15
+ var largestY = 0;
16
+ var gap = 0;
17
+ var row = {
18
+ left: paddingLeft,
19
+ anchor: attr.anchor,
20
+ phrases: []
21
+ }
22
+ if (klass)
23
+ row.klass = klass
24
+ rows.push(row)
25
+ for (var k = 0; k < str.length; k++) {
26
+ var thisWord = str[k];
27
+ var font = (thisWord.font) ? thisWord.font : getTextSize.attr(defFont, klass).font;
28
+ var phrase = {
29
+ content: thisWord.text,
30
+ }
31
+ if (font)
32
+ phrase.attrs = {
33
+ "font-family": getTextSize.getFamily(font.face),
34
+ "font-size": font.size,
35
+ "font-weight": font.weight,
36
+ "font-style": font.style,
37
+ "font-decoration": font.decoration,
38
+ }
39
+ //if (thisWord.text) {
40
+ row.phrases.push(phrase);
41
+ var size = getTextSize.calc(thisWord.text, font, klass);
42
+ largestY = Math.max(largestY, size.height);
43
+ if (thisWord.text[thisWord.text.length - 1] === ' ') {
44
+ gap = space.width
45
+ }
46
+ }
47
+ rows.push({ move: largestY });
48
+ }
49
+ }
50
+
51
+ module.exports = richText;