概要
codic で作成されたネーミングの左側にコピー用のボタンを設置します。
codicには大変お世話になっていて知人に紹介したのですが、コピーやケース変換の作業が手間だと言われたので作成しました。
動作確認はwindowsとfirefoxです。
機能
-
copy
をクリックするとネーミングをクリップボードにコピーします -
snake_case
を選択している(初めて開く場合は選択されています)とcopy
をクリックしている間左側に変換用ボタンが表示されます
マウスを押し込んだまま変換用ボタンにカーソルを移動してマウスを離すと、ケースを変換してコピーできます-
Pascal
でパスカルケース -
camel
でキャメルケース -
SNAKE
でアッパースネークケース -
ハイフネーション
で単語間をハイフンに -
変換なし
で単語間をスペースで繋ぎます
-
- 単語をクリックした際、区切られた単語が選択されるようになります
// ==UserScript==
// @name codic コピー補助
// @version 0.1
// @match https://codic.jp/engine
// @grant none
// ==/UserScript==
(function() {
'use strict';
const copyAreaId = 'copyArea';
let resolve;
const promise = new Promise(r => { resolve = r; });
const mo = new MutationObserver(mrArr => {
const translated = document.getElementById('translated');
if (translated) {
resolve(translated);
mo.disconnect();
}
});
mo.observe(document.body, {childList: true});
document.head.insertAdjacentHTML('beforeend', `<style type="text/css">
[id="copyArea"] .bl_changeCase {
text-align: right;
white-space: nowrap;
position: absolute;
top: 0;
left: -4px;
transform: translate(-100%, -37.5%);
display: none;
}
[id="copyArea"] .bl_changeCase > * + * {
margin-top: 4px;
}
[id="copyArea"].is_caseSnake :active + .bl_changeCase {
display: block;
}
</style>`);
promise.then(translated => {
const style = getComputedStyle(translated, '');
translated.insertAdjacentHTML('beforebegin', `<div id="${copyAreaId}" style="position: absolute; top: ${style['padding-top']}; left: ${style['padding-left']}; transform: translateX(-100%); z-index: 3;"></div>`);
const copyArea = document.getElementById(copyAreaId);
copyArea.addEventListener('mouseup', e => {
const btn = e.target;
if (! btn.matches('button[data-case]')) { return; }
translated.querySelectorAll('.dropdown-menu.with-arrow').forEach(n => n.remove());
const type = btn.dataset.case;
let str = btn.closest('[data-value]').dataset.value;
if (type === 'usnake') {
str = str.toUpperCase();
} else if (type === 'hyphenation') {
str = str.replace(/_/g, '-');
} else if (type === 'no-converting') {
str = str.replace(/_/g, ' ');
} else if (type !== 'snake') {
str = str.replace(/_.{1}/g, char => char[1].toUpperCase());
if (type === 'pascal') {
str = str.replace(/^.{1}/, char => char.toUpperCase());
}
}
navigator.clipboard.writeText(str);
});
translated.addEventListener('click', e => {
if (! e.target.matches('.translated-text')) { return; }
const range = new Range();
range.selectNodeContents(e.target);
const selection = document.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}, true);
(new MutationObserver(mrArr => {
const isCaseSnake = document.querySelector('#header .casing-nav-item .case-option.active_ .title').innerText.trim() === 'snake_case';
let html = '';
translated.querySelectorAll('.node-sentence').forEach(n => {
const height = n.closest('.wrapper').clientHeight;
const str = Array.from(n.querySelectorAll('.translated-text-wrapper, .translated-delimiter')).map(n => n.innerText.trim()).join('');
if (str) {
html += `<div style="height: ${height}px; position: relative;" data-value="${str}">
<div><button type="button" data-case="snake">copy</button></div>
<div class="bl_changeCase">
<div><button type="button" data-case="pascal">Pascal</button></div>
<div><button type="button" data-case="camel">camel</button></div>
<div><button type="button" data-case="usnake">SNAKE</button></div>
<div><button type="button" data-case="hyphenation">ハイフネーション</button></div>
<div><button type="button" data-case="no-converting">変換なし</button></div>
</div>
</div>`;
} else {
html += `<div style="height: ${height}px;"> </div>`;
}
});
copyArea.classList.toggle('is_caseSnake', isCaseSnake);
copyArea.innerHTML = html;
})).observe(translated, {childList: true, subtree: true});
});
})();