和声選択をより簡単にするブックマークレットを作りました。2020.05.14
↑のリンクをブックマークしてください(右クリックしてブックマーク追加かドラッグ&ドロップで)。
そして作曲ページを開いているときに、追加したブックマークをクリックしてください。
使用は自己責任で。動かなかったらごめんなさい
悪意あるコードがないか確認しましょう。Orpheus外にアクセスするコードが一切ないことはすぐわかると思います。(むしろヘボと罵られる可能性の方が高い)
javascript:void(
(()=>{
var oe = {
params: {},
palette: {},
};
oe.getDoc = function(){
var iframe = document.querySelector('iframe');
this.win = (iframe? iframe.contentWindow: window);
this.doc = this.win.document;
};
oe.prepareCSS = function(){
var style = this.doc.createElement('style');
style.textContent = `
body {
position: relative;
}
.label {
cursor: pointer;
}
.palette {
width: 200px;
position: absolute;
top: 0;
right: 0;
background: #eef;
height: 500px;
border: 1px solid #666;
border-radius: 1rem;
}
.palette select {
height: 300px;
width: 200px;
}
.palette input,
.palette audio {
width: 200px;
box-sizing: border-box;
}
`;
this.doc.body.appendChild(style);
};
oe.createPalette = function(){
var palette = this.doc.createElement('div');
palette.classList.add('palette');
var p = this.doc.createElement('p');
var textbox = this.doc.createElement('input');
textbox.type = 'text';
textbox.placeholder = '検索';
textbox.classList.add('search');
p.appendChild(textbox);
palette.appendChild(p);
var section = this.doc.createElement('p');
section.textContent = '--';
palette.insertBefore(section, palette.firstChild);
var audio = this.doc.createElement('audio');
audio.controls = true;
audio.preload = 'none';
palette.appendChild(audio);
this.palette.elem = palette;
this.palette.section = section;
this.palette.textbox = textbox;
this.palette.audio = audio;
textbox.addEventListener('input', this.palette.textbox_handler.bind(this), false);
};
oe.palette.textbox_handler = function(e){
var query = e.target.value.toLowerCase();
for(const op of Array.from(this.palette.select.options)){
op.style.display = (op.textContent.toLowerCase().indexOf(query) !== -1? "": "none");
}
};
oe.replaceHarmony = function(){
for(var harmony of Array.from(this.doc.querySelectorAll('select[name$=":harmony"]'))){
var input = this.doc.createElement('input');
input.type = 'hidden';
input.name = harmony.name;
input.value = harmony.value;
var label = this.doc.createElement('span');
label.classList.add('label');
label.textContent = harmony.selectedOptions[0].textContent;
label.dataset.name = harmony.name;
label.addEventListener('click', this.palette.label_handler.bind(this), false);
this.params[harmony.name] = {
input: input,
label: label,
};
harmony.removeAttribute('name');
harmony.parentNode.insertBefore(label, harmony);
harmony.parentNode.replaceChild(input, harmony);
if(this.palette.select === undefined){
var select = harmony;
select.size = '20';
this.palette.elem.insertBefore(select, this.palette.audio);
this.doc.body.appendChild(this.palette.elem);
select.addEventListener('change', this.palette.select_handler.bind(this), false);
this.palette.select = select;
}
}
};
oe.palette.label_handler = function(e){
this.palette.select.value = this.params[e.target.dataset.name].input.value;
this.palette.section.textContent = this.params[e.target.dataset.name].input.name;
var top = e.target.parentNode.getBoundingClientRect().top;
this.palette.elem.style.top = (top+this.win.pageYOffset)+'px';
};
oe.palette.select_handler = function(e){
var name = this.palette.section.textContent;
var filename = e.target.value.split('/').pop().split('.')[0];
this.palette.audio.src = `/samples/harmony/${filename}.mp3`;
if(name === "--") return;
this.params[name].input.value = e.target.value;
this.params[name].label.textContent = e.target.selectedOptions[0].textContent;
};
oe.run = function(){
this.getDoc();
if(this.win.oe) return;
this.prepareCSS();
this.createPalette();
this.replaceHarmony();
this.win.oe = this;
};
oe.run();
})()
);