LoginSignup
0
0

More than 3 years have passed since last update.

codicで変数名のコピーを補助するユーザースクリプト

Posted at

概要

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;">&nbsp;</div>`;
                }
            });

            copyArea.classList.toggle('is_caseSnake', isCaseSnake);
            copyArea.innerHTML = html;
        })).observe(translated, {childList: true, subtree: true});
    });
})();
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0