和声選択をより簡単にするブックマークレットを作りました。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(); })() );