abcjs 6.2.3 → 6.4.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 (75) hide show
  1. package/README.md +8 -0
  2. package/RELEASE.md +84 -1
  3. package/dist/abcjs-basic-min.js +2 -2
  4. package/dist/abcjs-basic.js +1775 -1034
  5. package/dist/abcjs-basic.js.map +1 -1
  6. package/dist/abcjs-plugin-min.js +2 -2
  7. package/index.js +3 -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/api/tune-metrics.js +18 -0
  12. package/src/data/abc_tune.js +13 -2
  13. package/src/edit/abc_editarea.js +4 -1
  14. package/src/parse/abc_parse.js +2 -0
  15. package/src/parse/abc_parse_directive.js +23 -16
  16. package/src/parse/abc_parse_header.js +22 -19
  17. package/src/parse/abc_tokenizer.js +72 -7
  18. package/src/parse/tune-builder.js +60 -1
  19. package/src/synth/abc_midi_flattener.js +40 -462
  20. package/src/synth/abc_midi_sequencer.js +25 -10
  21. package/src/synth/chord-track.js +562 -0
  22. package/src/synth/create-note-map.js +2 -1
  23. package/src/synth/create-synth.js +91 -42
  24. package/src/synth/synth-controller.js +6 -2
  25. package/src/tablatures/instruments/string-patterns.js +11 -0
  26. package/src/tablatures/instruments/{violin/violin-patterns.js → tab-string-patterns.js} +6 -6
  27. package/src/tablatures/instruments/{violin/tab-violin.js → tab-string.js} +13 -11
  28. package/src/tablatures/tab-absolute-elements.js +16 -7
  29. package/src/tablatures/tab-renderer.js +22 -9
  30. package/src/test/abc_parser_lint.js +14 -12
  31. package/src/write/creation/abstract-engraver.js +6 -2
  32. package/src/write/creation/add-chord.js +102 -82
  33. package/src/write/creation/add-text-if.js +2 -2
  34. package/src/write/creation/decoration.js +16 -9
  35. package/src/write/creation/elements/bottom-text.js +62 -47
  36. package/src/write/creation/elements/rich-text.js +51 -0
  37. package/src/write/creation/elements/tie-element.js +23 -0
  38. package/src/write/creation/elements/top-text.js +37 -11
  39. package/src/write/creation/glyphs.js +1 -1
  40. package/src/write/draw/absolute.js +4 -1
  41. package/src/write/draw/draw.js +13 -4
  42. package/src/write/draw/non-music.js +3 -1
  43. package/src/write/draw/relative.js +1 -1
  44. package/src/write/draw/tempo.js +1 -1
  45. package/src/write/draw/text.js +10 -0
  46. package/src/write/engraver-controller.js +62 -17
  47. package/src/write/helpers/classes.js +1 -1
  48. package/src/write/helpers/get-font-and-attr.js +8 -1
  49. package/src/write/helpers/get-text-size.js +8 -1
  50. package/src/write/interactive/create-analysis.js +50 -0
  51. package/src/write/interactive/find-selectable-element.js +24 -0
  52. package/src/write/interactive/selection.js +5 -45
  53. package/src/write/layout/layout-in-grid.js +83 -0
  54. package/src/write/layout/layout.js +29 -24
  55. package/src/write/layout/set-upper-and-lower-elements.js +2 -0
  56. package/src/write/layout/staff-group.js +2 -2
  57. package/src/write/layout/voice-elements.js +1 -1
  58. package/src/write/layout/voice.js +1 -1
  59. package/src/write/renderer.js +3 -0
  60. package/src/write/svg.js +30 -0
  61. package/temp.txt +3 -0
  62. package/types/index.d.ts +142 -38
  63. package/version.js +1 -1
  64. package/.github/workflows/tests.yml +0 -29
  65. package/abc2xml_239/abc2xml.html +0 -769
  66. package/abc2xml_239/abc2xml.py +0 -2248
  67. package/abc2xml_239/abc2xml_changelog.html +0 -124
  68. package/abc2xml_239/lazy-river.abc +0 -26
  69. package/abc2xml_239/lazy-river.xml +0 -3698
  70. package/abc2xml_239/mean-to-me.abc +0 -22
  71. package/abc2xml_239/mean-to-me.xml +0 -2954
  72. package/abc2xml_239/pyparsing.py +0 -3672
  73. package/abc2xml_239/pyparsing.pyc +0 -0
  74. package/src/tablatures/instruments/guitar/guitar-patterns.js +0 -23
  75. package/src/tablatures/instruments/guitar/tab-guitar.js +0 -48
@@ -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;
@@ -160,7 +160,7 @@ var stackedDecoration = function (decoration, width, abselem, yPos, positioning,
160
160
  var height = glyphs.symbolHeightInPitches(symbol) + 1; // adding a little padding so nothing touches.
161
161
  var y = getPlacement(placement);
162
162
  y = (placement === 'above') ? y + height / 2 : y - height / 2;// Center the element vertically.
163
- abselem.addFixedX(new RelativeElement(symbol, deltaX, glyphs.getSymbolWidth(symbol), y, { klass: 'ornament', thickness: glyphs.symbolHeightInPitches(symbol) }));
163
+ abselem.addFixedX(new RelativeElement(symbol, deltaX, glyphs.getSymbolWidth(symbol), y, { klass: 'ornament', thickness: glyphs.symbolHeightInPitches(symbol), position: placement }));
164
164
 
165
165
  incrementPlacement(placement, height);
166
166
  }
@@ -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,15 @@ 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
+ yPos.below = Math.min(yPos.below, minPitch);
359
+ var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, minPitch, accentAbove);
360
+ //if (hasOne) {
354
361
  // abselem.top = Math.max(yPos.above + 3, abselem.top); // TODO-PER: Not sure why we need this fudge factor.
355
- }
362
+ //}
356
363
  leftDecoration(decoration, abselem, roomtaken);
357
364
  };
358
365
 
@@ -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;
@@ -177,6 +177,29 @@ TieElem.prototype.calcSlurY = function () {
177
177
  } else
178
178
  this.endY = this.above && beamInterferes ? this.anchor2.highestVert : this.anchor2.pitch;
179
179
 
180
+ if (this.anchor1.scalex === 1) { // Need a way to tell if this is a grace note - if so then keep the slur as close as possible. TODO-PER-HACK: this should be more declaratively determined.
181
+ var hasBeam1 = !!this.anchor1.parent.beam
182
+ var hasBeam2 = !!this.anchor2.parent.beam
183
+ if (hasBeam1) {
184
+ var isLastInBeam = this.anchor1.parent === this.anchor1.parent.beam.elems[this.anchor1.parent.beam.elems.length-1]
185
+ if (!isLastInBeam) {
186
+ if (this.above)
187
+ this.startY = this.anchor1.parent.fixed.t
188
+ else
189
+ this.startY = this.anchor1.parent.fixed.b
190
+ }
191
+ }
192
+
193
+ if (hasBeam2) {
194
+ var isFirstInBeam = this.anchor2.parent === this.anchor2.parent.beam.elems[0]
195
+ if (!isFirstInBeam) {
196
+ if (this.above)
197
+ this.endY = this.anchor2.parent.fixed.t
198
+ else
199
+ this.endY = this.anchor2.parent.fixed.b
200
+ }
201
+ }
202
+ }
180
203
  } else if (this.anchor1) {
181
204
  this.startY = this.endY = this.anchor1.pitch;
182
205
  } else if (this.anchor2) {
@@ -1,6 +1,7 @@
1
1
  const addTextIf = require("../add-text-if");
2
+ const richText = require("./rich-text");
2
3
 
3
- function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, getTextSize) {
4
+ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) {
4
5
  this.rows = [];
5
6
 
6
7
  if (metaText.header && isPrint) {
@@ -18,12 +19,14 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
18
19
  var tAnchor = formatting.titleleft ? 'start' : 'middle';
19
20
  var tLeft = formatting.titleleft ? paddingLeft : paddingLeft + width / 2;
20
21
  if (metaText.title) {
21
- addTextIf(this.rows, { marginLeft: tLeft, text: metaText.title, font: 'titlefont', klass: 'title meta-top', marginTop: spacing.title, anchor: tAnchor, absElemType: "title", info: metaTextInfo.title, name: "title" }, getTextSize);
22
+ var klass = shouldAddClasses ? 'abcjs-title' : ''
23
+ richText(this.rows, metaText.title, "titlefont", klass, 'title', tLeft, {marginTop: spacing.title, anchor: tAnchor, absElemType: "title", info: metaTextInfo.title}, getTextSize)
22
24
  }
23
25
  if (lines.length) {
24
26
  var index = 0;
25
27
  while (index < lines.length && lines[index].subtitle) {
26
- addTextIf(this.rows, { marginLeft: tLeft, text: lines[index].subtitle.text, font: 'subtitlefont', klass: 'text meta-top subtitle', marginTop: spacing.subtitle, anchor: tAnchor, absElemType: "subtitle", info: lines[index].subtitle, name: "subtitle" }, getTextSize);
28
+ var klass = shouldAddClasses ? 'abcjs-text abcjs-subtitle' : ''
29
+ richText(this.rows, lines[index].subtitle.text, "subtitlefont", klass, 'subtitle', tLeft, {marginTop: spacing.subtitle, anchor: tAnchor, absElemType: "subtitle", info: lines[index].subtitle}, getTextSize)
27
30
  index++;
28
31
  }
29
32
  }
@@ -32,22 +35,45 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
32
35
  this.rows.push({ move: spacing.composer });
33
36
  if (metaText.rhythm && metaText.rhythm.length > 0) {
34
37
  var noMove = !!(metaText.composer || metaText.origin);
35
- addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: 'meta-top rhythm', absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize);
38
+ var klass = shouldAddClasses ? 'abcjs-rhythm' : ''
39
+ addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: klass, absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize);
36
40
  }
37
- var composerLine = "";
38
- if (metaText.composer) composerLine += metaText.composer;
39
- if (metaText.origin) composerLine += ' (' + metaText.origin + ')';
40
- if (composerLine.length > 0) {
41
- addTextIf(this.rows, { marginLeft: paddingLeft + width, text: composerLine, font: 'composerfont', klass: 'meta-top composer', anchor: "end", absElemType: "composer", info: metaTextInfo.composer, name: "composer" }, getTextSize);
41
+ var hasSimpleComposerLine = true
42
+ if (metaText.composer && typeof metaText.composer !== 'string')
43
+ hasSimpleComposerLine = false
44
+ if (metaText.origin && typeof metaText.origin !== 'string')
45
+ hasSimpleComposerLine = false
46
+
47
+ var composerLine = metaText.composer ? metaText.composer : '';
48
+ if (metaText.origin) {
49
+ if (typeof composerLine === 'string' && typeof metaText.origin === 'string')
50
+ composerLine += ' (' + metaText.origin + ')';
51
+ else if (typeof composerLine === 'string' && typeof metaText.origin !== 'string') {
52
+ composerLine = [{text:composerLine}]
53
+ composerLine.push({text:" ("})
54
+ composerLine = composerLine.concat(metaText.origin)
55
+ composerLine.push({text:")"})
56
+ } else {
57
+ composerLine.push({text:" ("})
58
+ composerLine = composerLine.concat(metaText.origin)
59
+ composerLine.push({text:")"})
60
+ }
61
+ }
62
+ if (composerLine) {
63
+ var klass = shouldAddClasses ? 'abcjs-composer' : ''
64
+ richText(this.rows, composerLine, 'composerfont', klass, "composer", paddingLeft+width, {anchor: "end", absElemType: "composer", info: metaTextInfo.composer, ingroup: true}, getTextSize)
42
65
  }
43
66
  }
44
67
 
45
68
  if (metaText.author && metaText.author.length > 0) {
46
- addTextIf(this.rows, { marginLeft: paddingLeft + width, text: metaText.author, font: 'composerfont', klass: 'meta-top author', anchor: "end", absElemType: "author", info: metaTextInfo.author, name: "author" }, getTextSize);
69
+ var klass = shouldAddClasses ? 'abcjs-author' : ''
70
+ richText(this.rows, metaText.author, 'composerfont', klass, "author", paddingLeft+width, {anchor: "end", absElemType: "author", info: metaTextInfo.author}, getTextSize)
47
71
  }
48
72
 
49
73
  if (metaText.partOrder && metaText.partOrder.length > 0) {
50
- addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.partOrder, font: 'partsfont', klass: 'meta-top part-order', absElemType: "partOrder", info: metaTextInfo.partOrder, name: "part-order" }, getTextSize);
74
+ var klass = shouldAddClasses ? 'abcjs-part-order' : ''
75
+ richText(this.rows, metaText.partOrder, 'partsfont', klass, "part-order", paddingLeft, {absElemType: "partOrder", info: metaTextInfo.partOrder, anchor: 'start'}, getTextSize)
76
+
51
77
  }
52
78
  }
53
79
 
@@ -86,7 +86,7 @@ var glyphs =
86
86
  's': { d: [['M', 4.47, -8.73], ['c', 0.09, 0.00, 0.36, -0.03, 0.57, -0.03], ['c', 0.75, 0.03, 1.29, 0.24, 1.71, 0.63], ['c', 0.51, 0.54, 0.66, 1.26, 0.36, 1.83], ['c', -0.24, 0.42, -0.63, 0.57, -1.11, 0.42], ['c', -0.33, -0.09, -0.60, -0.36, -0.60, -0.57], ['c', 0.00, -0.03, 0.06, -0.21, 0.15, -0.39], ['c', 0.12, -0.21, 0.15, -0.33, 0.18, -0.48], ['c', 0.00, -0.24, -0.06, -0.48, -0.15, -0.60], ['c', -0.15, -0.21, -0.42, -0.24, -0.75, -0.15], ['c', -0.27, 0.06, -0.48, 0.18, -0.69, 0.36], ['c', -0.39, 0.39, -0.51, 0.96, -0.33, 1.38], ['c', 0.09, 0.21, 0.42, 0.51, 0.78, 0.72], ['c', 1.11, 0.69, 1.59, 1.11, 1.89, 1.68], ['c', 0.21, 0.39, 0.24, 0.78, 0.15, 1.29], ['c', -0.18, 1.20, -1.17, 2.16, -2.52, 2.52], ['c', -1.02, 0.24, -1.95, 0.12, -2.70, -0.42], ['c', -0.72, -0.51, -0.99, -1.47, -0.60, -2.19], ['c', 0.24, -0.48, 0.72, -0.63, 1.17, -0.42], ['c', 0.33, 0.18, 0.54, 0.45, 0.57, 0.81], ['c', 0.00, 0.21, -0.03, 0.30, -0.33, 0.51], ['c', -0.33, 0.24, -0.39, 0.42, -0.27, 0.69], ['c', 0.06, 0.15, 0.21, 0.27, 0.45, 0.33], ['c', 0.30, 0.09, 0.87, 0.09, 1.20, 0.00], ['c', 0.75, -0.21, 1.23, -0.72, 1.29, -1.35], ['c', 0.03, -0.42, -0.15, -0.81, -0.54, -1.20], ['c', -0.24, -0.24, -0.48, -0.42, -1.41, -1.02], ['c', -0.69, -0.42, -1.05, -0.93, -1.05, -1.47], ['c', 0.00, -0.39, 0.12, -0.87, 0.30, -1.23], ['c', 0.27, -0.57, 0.78, -1.05, 1.38, -1.35], ['c', 0.24, -0.12, 0.63, -0.27, 0.90, -0.30], ['z']], w: 6.632, h: 8.758 },
87
87
  'z': { d: [['M', 2.64, -7.95], ['c', 0.36, -0.09, 0.81, -0.03, 1.71, 0.27], ['c', 0.78, 0.21, 0.96, 0.27, 1.74, 0.30], ['c', 0.87, 0.06, 1.02, 0.03, 1.38, -0.21], ['c', 0.21, -0.15, 0.33, -0.15, 0.48, -0.06], ['c', 0.15, 0.09, 0.21, 0.30, 0.15, 0.45], ['c', -0.03, 0.06, -1.26, 1.26, -2.76, 2.67], ['l', -2.73, 2.55], ['l', 0.54, 0.03], ['c', 0.54, 0.03, 0.72, 0.03, 2.01, 0.15], ['c', 0.36, 0.03, 0.90, 0.06, 1.20, 0.09], ['c', 0.66, 0.00, 0.81, -0.03, 1.02, -0.24], ['c', 0.30, -0.30, 0.39, -0.72, 0.27, -1.23], ['c', -0.06, -0.27, -0.06, -0.27, -0.03, -0.39], ['c', 0.15, -0.30, 0.54, -0.27, 0.69, 0.03], ['c', 0.15, 0.33, 0.27, 1.02, 0.27, 1.50], ['c', 0.00, 1.47, -1.11, 2.70, -2.52, 2.79], ['c', -0.57, 0.03, -1.02, -0.09, -2.01, -0.51], ['c', -1.02, -0.42, -1.23, -0.48, -2.13, -0.54], ['c', -0.81, -0.06, -0.96, -0.03, -1.26, 0.18], ['c', -0.12, 0.06, -0.24, 0.12, -0.27, 0.12], ['c', -0.27, 0.00, -0.45, -0.30, -0.36, -0.51], ['c', 0.03, -0.06, 1.32, -1.32, 2.91, -2.79], ['l', 2.88, -2.73], ['c', -0.03, 0.00, -0.21, 0.03, -0.42, 0.06], ['c', -0.21, 0.03, -0.78, 0.09, -1.23, 0.12], ['c', -1.11, 0.12, -1.23, 0.15, -1.95, 0.27], ['c', -0.72, 0.15, -1.17, 0.18, -1.29, 0.09], ['c', -0.27, -0.18, -0.21, -0.75, 0.12, -1.26], ['c', 0.39, -0.60, 0.93, -1.02, 1.59, -1.20], ['z']], w: 8.573, h: 8.743 },
88
88
  '+': { d: [['M', 3.48, -9.3], ['c', 0.18, -0.09, 0.36, -0.09, 0.54, 0.00], ['c', 0.18, 0.09, 0.24, 0.15, 0.33, 0.30], ['l', 0.06, 0.15], ['l', 0.00, 1.29], ['l', 0.00, 1.29], ['l', 1.29, 0.00], ['c', 1.23, 0.00, 1.29, 0.00, 1.41, 0.06], ['c', 0.06, 0.03, 0.15, 0.09, 0.18, 0.12], ['c', 0.12, 0.09, 0.21, 0.33, 0.21, 0.48], ['c', 0.00, 0.15, -0.09, 0.39, -0.21, 0.48], ['c', -0.03, 0.03, -0.12, 0.09, -0.18, 0.12], ['c', -0.12, 0.06, -0.18, 0.06, -1.41, 0.06], ['l', -1.29, 0.00], ['l', 0.00, 1.29], ['c', 0.00, 1.23, 0.00, 1.29, -0.06, 1.41], ['c', -0.09, 0.18, -0.15, 0.24, -0.30, 0.33], ['c', -0.21, 0.09, -0.39, 0.09, -0.57, 0.00], ['c', -0.18, -0.09, -0.24, -0.15, -0.33, -0.33], ['c', -0.06, -0.12, -0.06, -0.18, -0.06, -1.41], ['l', 0.00, -1.29], ['l', -1.29, 0.00], ['c', -1.23, 0.00, -1.29, 0.00, -1.41, -0.06], ['c', -0.18, -0.09, -0.24, -0.15, -0.33, -0.33], ['c', -0.09, -0.18, -0.09, -0.36, 0.00, -0.54], ['c', 0.09, -0.18, 0.15, -0.24, 0.33, -0.33], ['l', 0.15, -0.06], ['l', 1.26, 0.00], ['l', 1.29, 0.00], ['l', 0.00, -1.29], ['c', 0.00, -1.23, 0.00, -1.29, 0.06, -1.41], ['c', 0.09, -0.18, 0.15, -0.24, 0.33, -0.33], ['z']], w: 7.507, h: 7.515 },
89
- ',': { 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']], w: 3.452, h: 8.143 },
89
+ ',': { 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']], w: 3.452, h: 8.143 },
90
90
  '-': { d: [['M', 0.18, -5.34], ['c', 0.09, -0.06, 0.15, -0.06, 2.31, -0.06], ['c', 2.46, 0.00, 2.37, 0.00, 2.46, 0.21], ['c', 0.12, 0.21, 0.03, 0.42, -0.15, 0.54], ['c', -0.09, 0.06, -0.15, 0.06, -2.28, 0.06], ['c', -2.16, 0.00, -2.22, 0.00, -2.31, -0.06], ['c', -0.27, -0.15, -0.27, -0.54, -0.03, -0.69], ['z']], w: 5.001, h: 0.81 },
91
91
  '.': { d: [['M', 1.32, -3.36], ['c', 1.05, -0.27, 2.10, 0.57, 2.10, 1.65], ['c', 0.00, 1.08, -1.05, 1.92, -2.10, 1.65], ['c', -0.90, -0.21, -1.50, -1.14, -1.26, -2.04], ['c', 0.12, -0.63, 0.63, -1.11, 1.26, -1.26], ['z']], w: 3.413, h: 3.402 },
92
92
  'scripts.wedge': { d: [['M', -3.66, -7.44], ['c', 0.06, -0.09, 0.00, -0.09, 0.81, 0.03], ['c', 1.86, 0.30, 3.84, 0.30, 5.73, 0.00], ['c', 0.78, -0.12, 0.72, -0.12, 0.78, -0.03], ['c', 0.15, 0.15, 0.12, 0.24, -0.24, 0.60], ['c', -0.93, 0.93, -1.98, 2.76, -2.67, 4.62], ['c', -0.30, 0.78, -0.51, 1.71, -0.51, 2.13], ['c', 0.00, 0.15, 0.00, 0.18, -0.06, 0.27], ['c', -0.12, 0.09, -0.24, 0.09, -0.36, 0.00], ['c', -0.06, -0.09, -0.06, -0.12, -0.06, -0.27], ['c', 0.00, -0.42, -0.21, -1.35, -0.51, -2.13], ['c', -0.69, -1.86, -1.74, -3.69, -2.67, -4.62], ['c', -0.36, -0.36, -0.39, -0.45, -0.24, -0.60], ['z']], w: 7.49, h: 7.752 },
@@ -16,7 +16,10 @@ function drawAbsolute(renderer, params, bartop, selectables, staffPos) {
16
16
  drawTempo(renderer, child);
17
17
  break;
18
18
  default:
19
- drawRelativeElement(renderer, child, bartop);
19
+ var el = drawRelativeElement(renderer, child, bartop);
20
+ if (child.type === "symbol" && child.c && child.c.indexOf('notehead') >= 0) {
21
+ el.setAttribute('class', 'abcjs-notehead')
22
+ }
20
23
  }
21
24
  }
22
25
  var klass = params.type;