28
28
* The Rainbow Song (Crackazat rework)
29
29
*/
30
30
const TitleRemixRegexp =
31
- / ^ \s * ( .+ ) \s + \( \s * ( .+ ) \s + (?: (?: r e ) ? m i x | r e - ? (?: [ d r ] u b | e d i t | w o r k ) | e d i t ) .* \) / i;
32
-
33
- const AddIconUri = 'https://staticbrainz.org/MB/add-e585eab.png' ;
34
- // <option value="153"> remixer</option>
35
- const RemixerOptionValue = '153' ;
36
- // <option value="230"> remix of</option>
37
- const RemixOfOptionValue = '230' ;
31
+ / ^ \s * ( .+ ) \s + \( \s * ( .+ ) \s + (?: (?: r e - ? ) ? (?: [ d r ] u b | e d i t | m i x ) | r e - ? w o r k ) .* \) / i;
38
32
39
33
// This code is based on:
40
34
// https://stackoverflow.com/questions/42795059/programmatically-fill-reactjs-form
@@ -60,17 +54,19 @@ function setElementValue(element, value, event = 'input') {
60
54
element . dispatchEvent ( new Event ( event , { bubbles : true } ) ) ;
61
55
}
62
56
63
- function addStyleElement ( ) {
64
- const style = document . createElement ( 'style' ) ;
65
- style . type = 'text/css' ;
66
- document . head . appendChild ( style ) ;
67
- style . appendChild (
68
- document . createTextNode ( '.add-rc { display: inline-block; }' )
69
- ) ;
57
+ function tabToConfirmFirstOption ( element ) {
58
+ const event = new KeyboardEvent ( 'keydown' , {
59
+ key : 'Tab' ,
60
+ keyCode : 9 ,
61
+ which : 9 ,
62
+ bubbles : true ,
63
+ cancelable : true ,
64
+ } ) ;
65
+ element . dispatchEvent ( event ) ;
70
66
}
71
67
72
68
function addRemixCreditLinks ( ) {
73
- const recordings = document . getElementsByClassName ( ' recording') ;
69
+ const recordings = document . querySelectorAll ( 'td. recording') ;
74
70
const releaseArtists = Array . from (
75
71
document
76
72
. getElementsByClassName ( 'subheader' ) [ 0 ]
@@ -92,47 +88,46 @@ function addRemixCreditLinks() {
92
88
linkTypes [ link . innerText ] = 1 ;
93
89
}
94
90
95
- let span = document . createElement ( 'span ' ) ;
96
- if ( linkTypes [ 'remixer' ] ) {
97
- span . className = 'add-rc btn disabled' ;
91
+ let button = document . createElement ( 'button ' ) ;
92
+ if ( linkTypes [ 'remixer: ' ] ) {
93
+ button . className = 'add-item with-label btn disabled' ;
98
94
} else {
99
- span . className = 'add-rc btn ' ;
100
- span . onclick = addRemixCreditClickHandler ;
101
- span . setAttribute ( 'data-remixer' , matches [ 2 ] ) ;
95
+ button . className = 'add-item with-label ' ;
96
+ button . onclick = addRemixCreditClickHandler ;
97
+ button . setAttribute ( 'data-remixer' , matches [ 2 ] ) ;
102
98
}
103
99
104
- span . innerHTML = `
105
- <img class="bottom" src="${ AddIconUri } ">
100
+ button . innerHTML = `
106
101
Add "remixer" credit
107
102
` ;
108
- recording . appendChild ( span ) ;
103
+ recording . appendChild ( button ) ;
109
104
recording . appendChild ( document . createTextNode ( '\n' ) ) ;
110
105
111
- span = document . createElement ( 'span ' ) ;
112
- if ( linkTypes [ 'remix of' ] ) {
113
- span . className = 'add-rc btn disabled' ;
106
+ button = document . createElement ( 'button ' ) ;
107
+ if ( linkTypes [ 'remix of: ' ] ) {
108
+ button . className = 'add-item with-label btn disabled' ;
114
109
} else {
115
- let trackArtists = Array . from (
116
- recording
117
- . getElementsByTagName ( 'span' ) [ 1 ]
118
- . getElementsByTagName ( 'bdi' )
119
- ) . map ( bdi => bdi . innerText ) ;
110
+ const trackArtistElement = recording
111
+ . getElementsByTagName ( 'span' ) [ 1 ] ;
112
+
113
+ let trackArtists = trackArtistElement ? Array . from (
114
+ trackArtistElement . getElementsByTagName ( 'bdi' )
115
+ ) . map ( bdi => bdi . innerText ) : [ ] ;
120
116
if ( ! trackArtists . length ) {
121
117
trackArtists = releaseArtists ;
122
118
}
123
119
// recording search will be pre-filled with title and artists to improve the results
124
120
const recordingQuery = `${ matches [ 1 ] } ${ trackArtists . join ( ' ' ) } ` ;
125
121
126
- span . className = 'add-rc btn ' ;
127
- span . onclick = addRemixCreditClickHandler ;
128
- span . setAttribute ( 'data-remix-of' , recordingQuery ) ;
122
+ button . className = 'add-item with-label ' ;
123
+ button . onclick = addRemixCreditClickHandler ;
124
+ button . setAttribute ( 'data-remix-of' , recordingQuery ) ;
129
125
}
130
126
131
- span . innerHTML = `
132
- <img class="bottom" src="${ AddIconUri } ">
127
+ button . innerHTML = `
133
128
Add "remix of" credit
134
129
` ;
135
- recording . appendChild ( span ) ;
130
+ recording . appendChild ( button ) ;
136
131
}
137
132
}
138
133
@@ -143,48 +138,61 @@ function addRemixCreditClickHandler(event) {
143
138
const remixer = this . getAttribute ( 'data-remixer' ) ;
144
139
const remixOf = this . getAttribute ( 'data-remix-of' ) ;
145
140
146
- const addRel = recording . getElementsByClassName ( ' add-rel' ) [ 0 ] ;
141
+ const addRel = recording . querySelector ( 'button. add-relationship' ) ;
147
142
addRel . click ( ) ;
148
143
149
144
if ( remixer ) {
150
145
// wait 250ms for the dialog to be added to the DOM
151
146
window . setTimeout ( function ( ) {
152
- const dialog = document . getElementById ( 'dialog' ) ;
153
- const linkType = dialog . getElementsByClassName ( 'link-type' ) [ 0 ] ;
154
- setElementValue ( linkType , RemixerOptionValue , 'change' ) ;
155
-
156
- const name = dialog . getElementsByClassName ( 'name' ) [ 0 ] ;
157
- if ( remixer ) {
158
- setElementValue ( name , remixer ) ;
159
- } else {
160
- name . focus ( ) ;
147
+ const dialog = document . getElementById ( 'add-relationship-dialog' ) ;
148
+ const entityType = dialog . querySelector ( 'select.entity-type' ) ;
149
+ setElementValue ( entityType , 'artist' , 'change' ) ;
150
+
151
+ const linkType = dialog . querySelector ( 'input.relationship-type' ) ;
152
+ setElementValue ( linkType , 'remixed / remixer' ) ;
153
+ tabToConfirmFirstOption ( linkType ) ;
154
+
155
+ const name = dialog . querySelector ( 'input.relationship-target' ) ;
156
+ setElementValue ( name , remixer ) ;
157
+ const search = name . parentElement . querySelector ( 'button.search' ) ;
158
+ if ( search ) {
159
+ window . setTimeout ( function ( ) {
160
+ search . click ( ) ;
161
+ name . focus ( ) ;
162
+ } , 100 ) ;
161
163
}
162
164
} , 250 ) ;
163
165
} else if ( remixOf ) {
164
166
// wait 250ms for the dialog to be added to the DOM
165
167
window . setTimeout ( function ( ) {
166
- const dialog = document . getElementById ( 'dialog' ) ;
167
- const entityType = dialog . getElementsByClassName ( ' entity-type') [ 0 ] ;
168
+ const dialog = document . getElementById ( 'add-relationship- dialog' ) ;
169
+ const entityType = dialog . querySelector ( 'select. entity-type') ;
168
170
setElementValue ( entityType , 'recording' , 'change' ) ;
169
171
170
172
// wait another 250ms for the link-type select options to be updated
171
173
window . setTimeout ( function ( ) {
172
- const linkType = dialog . getElementsByClassName ( 'link-type' ) [ 0 ] ;
173
- setElementValue ( linkType , RemixOfOptionValue , 'change' ) ;
174
-
175
- const name = dialog . getElementsByClassName ( 'name' ) [ 0 ] ;
176
- if ( remixOf ) {
177
- setElementValue ( name , remixOf ) ;
178
- } else {
179
- name . focus ( ) ;
174
+ const linkType = dialog . querySelector ( 'input.relationship-type' ) ;
175
+ setElementValue ( linkType , 'remix of / has remixes' ) ;
176
+ tabToConfirmFirstOption ( linkType ) ;
177
+
178
+ const name = dialog . querySelector ( 'input.relationship-target' ) ;
179
+ setElementValue ( name , remixOf ) ;
180
+ const search = name . parentElement . querySelector ( 'button.search' ) ;
181
+ if ( search ) {
182
+ window . setTimeout ( function ( ) {
183
+ search . click ( ) ;
184
+ name . focus ( ) ;
185
+ } , 100 ) ;
180
186
}
181
187
} , 250 ) ;
182
188
} , 250 ) ;
183
189
}
184
190
}
185
191
186
192
// wait 500ms for the page to fully initialise
187
- window . setTimeout ( function ( ) {
188
- addStyleElement ( ) ;
189
- addRemixCreditLinks ( ) ;
193
+ const intervalId = window . setInterval ( function ( ) {
194
+ if ( ! document . querySelector ( '.loading-message' ) ) {
195
+ window . clearInterval ( intervalId ) ;
196
+ addRemixCreditLinks ( ) ;
197
+ }
190
198
} , 500 ) ;
0 commit comments