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.
- package/README.md +4 -0
- package/RELEASE.md +40 -1
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +751 -416
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/index.js +2 -0
- package/package.json +1 -1
- package/plugin.js +1 -1
- package/src/api/abc_tablatures.js +48 -13
- package/src/parse/abc_parse_directive.js +17 -16
- package/src/parse/abc_parse_header.js +22 -19
- package/src/parse/abc_tokenizer.js +72 -7
- package/src/parse/tune-builder.js +60 -1
- package/src/synth/synth-controller.js +6 -2
- package/src/tablatures/instruments/string-patterns.js +11 -0
- package/src/tablatures/instruments/{guitar/guitar-patterns.js → tab-string-patterns.js} +6 -6
- package/src/tablatures/instruments/{violin/tab-violin.js → tab-string.js} +13 -11
- package/src/tablatures/tab-absolute-elements.js +16 -7
- package/src/tablatures/tab-renderer.js +22 -9
- package/src/test/abc_parser_lint.js +13 -12
- package/src/write/creation/abstract-engraver.js +3 -2
- package/src/write/creation/add-chord.js +102 -82
- package/src/write/creation/add-text-if.js +2 -2
- package/src/write/creation/decoration.js +14 -8
- package/src/write/creation/elements/bottom-text.js +62 -47
- package/src/write/creation/elements/rich-text.js +51 -0
- package/src/write/creation/elements/top-text.js +37 -11
- package/src/write/creation/glyphs.js +1 -1
- package/src/write/draw/absolute.js +4 -1
- package/src/write/draw/draw.js +13 -4
- package/src/write/draw/non-music.js +3 -1
- package/src/write/draw/relative.js +1 -1
- package/src/write/draw/tempo.js +1 -1
- package/src/write/draw/text.js +10 -0
- package/src/write/engraver-controller.js +54 -13
- package/src/write/helpers/classes.js +1 -1
- package/src/write/helpers/get-font-and-attr.js +8 -1
- package/src/write/helpers/get-text-size.js +8 -1
- package/src/write/svg.js +30 -0
- package/temp.txt +50 -0
- package/types/index.d.ts +46 -6
- package/version.js +1 -1
- package/.github/workflows/tests.yml +0 -29
- package/src/tablatures/instruments/guitar/tab-guitar.js +0 -48
- 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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
234
|
-
staffGroup.
|
|
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
|
|
55
|
-
|
|
56
|
-
var
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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,
|
|
13
|
-
var klass = '
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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;
|