Skip to content

Commit bca254a

Browse files
authored
Merge pull request metabrainz#1966 from reosarevok/MBS-11430
MBS-11430: Convert format_setlist to Javascript
2 parents c47b209 + a9fbdd3 commit bca254a

File tree

6 files changed

+155
-60
lines changed

6 files changed

+155
-60
lines changed

babel.config.js

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ module.exports = function (api) {
3030
['@babel/plugin-transform-react-jsx', {
3131
runtime: 'automatic',
3232
}],
33-
'@babel/plugin-transform-react-constant-elements',
3433
['@babel/plugin-transform-runtime', {
3534
corejs: false,
3635
helpers: true,

lib/MusicBrainz/Server/Entity/Event.pm

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use MooseX::Types::Structured qw( Dict );
1818
use MooseX::Types::Moose qw( ArrayRef Object Str );
1919
use MusicBrainz::Server::Data::Utils qw( boolean_to_json non_empty );
2020
use MusicBrainz::Server::Entity::Util::JSON qw( add_linked_entity to_json_object );
21-
use MusicBrainz::Server::Filters qw( format_setlist );
2221
use MusicBrainz::Server::Types qw( Time );
2322
use List::UtilsBy qw( uniq_by );
2423

@@ -130,7 +129,7 @@ around TO_JSON => sub {
130129
entity => to_json_object($_->{entity}),
131130
}, $self->all_places],
132131
related_series => [map { $_->id } @related_series],
133-
(non_empty($setlist) ? (setlist => format_setlist($setlist)) : ()),
132+
(non_empty($setlist) ? (setlist => $setlist) : ()),
134133
time => $self->formatted_time,
135134
};
136135
};

lib/MusicBrainz/Server/Filters.pm

+1-55
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use Try::Tiny;
1616
use URI::Escape;
1717

1818
use Sub::Exporter -setup => {
19-
exports => [qw( format_editnote format_setlist format_wikitext )]
19+
exports => [qw( format_editnote format_wikitext )]
2020
};
2121

2222
sub format_length
@@ -25,60 +25,6 @@ sub format_length
2525
return MusicBrainz::Server::Track::FormatTrackLength($ms);
2626
}
2727

28-
sub format_setlist {
29-
my ($text) = @_;
30-
31-
# Encode < and >
32-
$text =~ s/</&lt;/g;
33-
$text =~ s/>/&gt;/g;
34-
35-
# Lines starting with @ are artists
36-
$text =~ s/^@ ([^\r\n]*)/format_setlist_artist($1)/meg;
37-
38-
# Lines starting with * are works
39-
$text =~ s/^\* ([^\r\n]*)/format_setlist_work($1)/meg;
40-
41-
# Lines starting with # are comments
42-
$text =~ s/^# ([^\r\n]*)/<span class=\"comment\">$1<\/span>/mg;
43-
44-
# Fix newlines
45-
$text =~ s/(\015\012|\012\015|\012|\015)/<br\/>/g;
46-
47-
return $text;
48-
}
49-
50-
sub format_setlist_artist {
51-
my ($line) = @_;
52-
53-
$line =~ s/
54-
\[
55-
([0-9a-f]{8} -
56-
[0-9a-f]{4} -
57-
[0-9a-f]{4} -
58-
[0-9a-f]{4} -
59-
[0-9a-f]{12})(?:\|([^\]]+))?\]
60-
/_make_link("artist",$1,$2)/eixg;
61-
62-
$line = "<strong>Artist: $line</strong>";
63-
64-
return $line;
65-
}
66-
67-
sub format_setlist_work {
68-
my ($line) = @_;
69-
70-
$line =~ s/
71-
\[
72-
([0-9a-f]{8} -
73-
[0-9a-f]{4} -
74-
[0-9a-f]{4} -
75-
[0-9a-f]{4} -
76-
[0-9a-f]{12})(?:\|([^\]]+))?\]
77-
/_make_link("work",$1,$2)/eixg;
78-
79-
return $line;
80-
}
81-
8228
sub format_wikitext
8329
{
8430
my ($text) = @_;

root/event/EventIndex.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as React from 'react';
1212
import Annotation from '../static/scripts/common/components/Annotation';
1313
import WikipediaExtract
1414
from '../static/scripts/common/components/WikipediaExtract';
15-
import expand2react from '../static/scripts/common/i18n/expand2react';
15+
import formatSetlist from '../static/scripts/common/utility/formatSetlist';
1616
import CleanupBanner from '../components/CleanupBanner';
1717
import Relationships from '../components/Relationships';
1818
import * as manifest from '../static/manifest';
@@ -54,7 +54,7 @@ const EventIndex = ({
5454
<>
5555
<h2 className="setlist">{l('Setlist')}</h2>
5656
<p className="setlist">
57-
{expand2react(setlist)}
57+
{formatSetlist(setlist)}
5858
</p>
5959
</>
6060
) : null}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* @flow strict-local
3+
* Copyright (C) 2021 MetaBrainz Foundation
4+
*
5+
* This file is part of MusicBrainz, the open internet music database,
6+
* and is licensed under the GPL version 2, or (at your option) any
7+
* later version: http://www.gnu.org/licenses/gpl-2.0.txt
8+
*/
9+
10+
import * as React from 'react';
11+
12+
function setlistLink(entityType, entityGid, content) {
13+
let formattedContent = content;
14+
if (!nonEmpty(formattedContent)) {
15+
formattedContent = entityType + ':' + entityGid;
16+
}
17+
18+
return (
19+
<a href={`/${entityType}/${entityGid}`}>
20+
{formattedContent}
21+
</a>
22+
);
23+
}
24+
25+
const linkRegExp =
26+
/^\[([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\|([^\]]+))?\]/i;
27+
28+
function formatSetlistArtist(entityGid, content) {
29+
return (
30+
<strong>
31+
{addColonText(l('Artist'))}
32+
{' '}
33+
{setlistLink('artist', entityGid, content)}
34+
</strong>
35+
);
36+
}
37+
38+
function formatSetlistWork(entityGid, content) {
39+
return setlistLink('work', entityGid, content);
40+
}
41+
42+
export default function formatSetlist(
43+
setlistText: string,
44+
): Expand2ReactOutput {
45+
const rawLines = setlistText.split(/(?:\r\n|\n\r|\r|\n)/);
46+
const elements = [];
47+
48+
for (const rawLine of rawLines) {
49+
if (!nonEmpty(rawLine)) {
50+
elements.push(<br />);
51+
continue;
52+
}
53+
54+
const symbol = rawLine.substring(0, 2);
55+
const line = rawLine.substring(2);
56+
let entityType;
57+
58+
switch (symbol) {
59+
// Lines starting with @ are artists
60+
case '@ ':
61+
entityType = 'artist';
62+
break;
63+
64+
// Lines starting with * are works
65+
case '* ':
66+
entityType = 'work';
67+
break;
68+
69+
// Lines starting with # are comments
70+
case '# ':
71+
elements.push(<span className="comment">{line}</span>);
72+
break;
73+
74+
// Lines that don't start with a symbol are ignored
75+
}
76+
77+
if (entityType) {
78+
const startingBracketRegExp = /\[/g;
79+
80+
let match;
81+
let lastIndex = 0;
82+
83+
while ((match = startingBracketRegExp.exec(line))) {
84+
const textBeforeMatch = line.substring(lastIndex, match.index);
85+
elements.push(textBeforeMatch);
86+
lastIndex = match.index;
87+
88+
const remainder = line.substring(match.index);
89+
const linkMatch = remainder.match(linkRegExp);
90+
91+
if (linkMatch) {
92+
const [linkMatchText, entityGid, content] = linkMatch;
93+
switch (entityType) {
94+
case 'artist':
95+
elements.push(formatSetlistArtist(entityGid, content));
96+
break;
97+
case 'work':
98+
elements.push(formatSetlistWork(entityGid, content));
99+
break;
100+
}
101+
lastIndex += linkMatchText.length;
102+
}
103+
}
104+
105+
elements.push(line.substring(lastIndex));
106+
}
107+
108+
elements.push(<br />);
109+
}
110+
111+
return React.createElement(React.Fragment, null, ...elements);
112+
}

root/static/scripts/tests/utility.js

+39
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* later version: http://www.gnu.org/licenses/gpl-2.0.txt
77
*/
88

9+
import * as ReactDOMServer from 'react-dom/server';
910
import test from 'tape';
1011

1112
import formatDate from '../common/utility/formatDate';
@@ -15,6 +16,7 @@ import compareDates, {
1516
compareDatePeriods,
1617
} from '../common/utility/compareDates';
1718
import formatDatePeriod from '../common/utility/formatDatePeriod';
19+
import formatSetlist from '../common/utility/formatSetlist';
1820
import formatTrackLength from '../common/utility/formatTrackLength';
1921
import parseDate from '../common/utility/parseDate';
2022
import * as dates from '../edit/utility/dates';
@@ -563,3 +565,40 @@ test('formatUserDate', function (t) {
563565
'%H ranges from 00-23',
564566
);
565567
});
568+
569+
test('formatSetlist', function (t) {
570+
t.plan(1);
571+
572+
const setlist =
573+
'@ pre-text [e1af2f0d-c685-4e83-a27d-b27e79787aab|artist 1] mid-text ' +
574+
'[0eda70b7-c77b-4775-b1db-5b0e5a3ca4c1|artist 2] post-text\n\r\n' +
575+
'* e [b831b5a4-e1a9-4516-bb50-b6eed446fc9b|work 1] [not a link]\r' +
576+
'@ plain text artist\n' +
577+
'# comment [b831b5a4-e1a9-4516-bb50-b6eed446fc9b|not a link]\r\n' +
578+
'# comment <a href="#">also not a link</a>\r\n' +
579+
'@ nor a link <a href="#">here</a>\n\r' +
580+
'* plain text work\n' +
581+
'ignored!\r\n';
582+
583+
t.equal(
584+
ReactDOMServer.renderToStaticMarkup(formatSetlist(setlist)),
585+
'pre-text <strong>' +
586+
'Artist: ' +
587+
'<a href="/artist/e1af2f0d-c685-4e83-a27d-b27e79787aab">artist 1</a>' +
588+
'</strong> mid-text ' +
589+
'<strong>Artist: ' +
590+
'<a href="/artist/0eda70b7-c77b-4775-b1db-5b0e5a3ca4c1">artist 2</a>' +
591+
'</strong> post-text<br/><br/>' +
592+
'e <a href="/work/b831b5a4-e1a9-4516-bb50-b6eed446fc9b">work 1</a> ' +
593+
'[not a link]<br/>' +
594+
'plain text artist<br/>' +
595+
'<span class="comment">' +
596+
'comment [b831b5a4-e1a9-4516-bb50-b6eed446fc9b|not a link]' +
597+
'</span><br/>' +
598+
'<span class="comment">' +
599+
'comment &lt;a href=&quot;#&quot;&gt;also not a link&lt;/a&gt;' +
600+
'</span><br/>' +
601+
'nor a link &lt;a href=&quot;#&quot;&gt;here&lt;/a&gt;<br/>' +
602+
'plain text work<br/><br/><br/>',
603+
);
604+
});

0 commit comments

Comments
 (0)