GNU/skin/board/outline_target/write/write.script.php
<script>
$(function() {
    function parseNumber(value) {
        const cleaned = String(value || '').replace(/[^0-9.-]/g, '');
        const parsed = parseFloat(cleaned);
        return Number.isFinite(parsed) ? parsed : 0;
    }

    function formatAmount(value) {
        if (!Number.isFinite(value)) return '0';
        return Math.round(value).toLocaleString('ko-KR');
    }

    function formatRate(value) {
        if (!Number.isFinite(value)) return '0.00';
        return value.toFixed(2);
    }

    function nowForDatetimeLocal() {
        const date = new Date();
        const y = date.getFullYear();
        const m = String(date.getMonth() + 1).padStart(2, '0');
        const d = String(date.getDate()).padStart(2, '0');
        const h = String(date.getHours()).padStart(2, '0');
        const i = String(date.getMinutes()).padStart(2, '0');
        return `${y}-${m}-${d}T${h}:${i}`;
    }

    function updateProfitFields() {
        const base = parseNumber($('#id_x2_base_amount').val());
        const current = parseNumber($('#id_x2_current_asset').val());
        const target = parseNumber($('#id_x2_target_amount').val());

        const profitAmount = current - base;
        const profitRate = base !== 0 ? (profitAmount / base) * 100 : 0;

        let reachRate = 0;
        const denominator = target - base;
        if (denominator !== 0) {
            reachRate = ((current - base) / denominator) * 100;
        }

        $('#id_x2_profit_amount').val(formatAmount(profitAmount));
        $('#id_x2_profit_rate').val(formatRate(profitRate));
        $('#id_x2_reach_rate').val(formatRate(reachRate));
    }

    function updateUnitRateFields() {
        const unitBase = parseNumber($('#id_x2_unit_base').val());
        const unitAdd = parseNumber($('#id_x2_unit_add').val());
        const unitMax = parseNumber($('#id_x2_unit_max').val());

        const baseIncreaseRate = unitBase !== 0 ? ((unitAdd - unitBase) / unitBase) * 100 : 0;
        const maxIncreaseRate = unitBase !== 0 ? ((unitMax - unitBase) / unitBase) * 100 : 0;

        $('#id_x2_base_increase_rate').val(formatRate(baseIncreaseRate));
        $('#id_x2_max_increase_rate').val(formatRate(maxIncreaseRate));
    }

    function syncCompleteDatetime() {
        if ($('#id_x2_run').is(':checked') && !$('#id_date_end').val()) {
            $('#id_date_end').val(nowForDatetimeLocal());
        }
    }

    const existCoins = <?php echo $exist_json; ?>;
    const currentVal = "<?php echo $subject; ?>";
    let finalSymbols = [];

    const fetchLinear  = $.ajax({ url: "https://api.bybit.com/v5/market/instruments-info?category=linear&limit=1000" });
    const fetchInverse = $.ajax({ url: "https://api.bybit.com/v5/market/instruments-info?category=inverse&limit=1000" });

    $.when(fetchLinear, fetchInverse).done(function(resLinear, resInverse) {
        if (resLinear[0].retCode === 0 && resLinear[0].result.list) {
            resLinear[0].result.list.forEach(item => {
                if(item.symbol.endsWith('USDT')) finalSymbols.push(item.symbol);
            });
        }

        let filtered = [...new Set(finalSymbols)].filter(symbol => {
            return !existCoins.includes(symbol) || symbol === currentVal;
        });
        filtered.sort((a, b) => a.localeCompare(b));

        const $select = $('#coin_select');
        $select.empty().append('<option value="">USDT 자산 선택</option>');
        filtered.forEach(symbol => {
            const selected = (symbol === currentVal) ? 'selected' : '';
            $select.append('<option value="' + symbol + '" ' + selected + '>' + symbol + '</option>');
        });
        updateFeedback();

    }).fail(function() {
        $('#coin_select').empty().append('<option value="">API 연결 오류</option>');
    });

    function updateFeedback() {
        const state = $('#id_x2_run').is(':checked') ? '활성(ON)' : '중지(OFF)';
        $('#res_state').text(state).css('color', $('#id_x2_run').is(':checked') ? '#00d4ff' : '#ff2d55');
        $('#res_coin').text($('#coin_select').val() || '-');
        $('#res_korean_name').text($('#id_x2_korean_name').val() || '-');
        $('#res_cat').text($('#id_ca_name option:selected').text() || '-');
        $('#res_mode').text(($('#id_x2_ca2 option:selected').text() || '-') + ' / ' + ($('#id_x2_ca3 option:selected').text() || '-'));
        $('#res_time').text($('#id_date').val() + ' ' + $('#id_time').val());
        $('#res_ver').text($('#id_x2_ver').val() || '-');
    }
    $('input, select').on('change keyup input', updateFeedback);
    setTimeout(updateFeedback, 500);

    $('#id_x2_memo_button').on('change', function() {
        const $panel = $('#memo_panel');
        if ($(this).is(':checked')) {
            $panel.removeClass('is-close').addClass('is-open').stop(true, true).slideDown(180);
        } else {
            $panel.removeClass('is-open').addClass('is-close').stop(true, true).slideUp(180);
            $('#id_x2_memo_clean').prop('checked', false);
        }
    });

    if ($('#id_x2_memo_button').is(':checked')) {
        $('#memo_panel').removeClass('is-close').addClass('is-open').show();
    } else {
        $('#memo_panel').removeClass('is-open').addClass('is-close').hide();
    }

    $('#id_x2_base_amount, #id_x2_current_asset, #id_x2_target_amount').on('keyup change input', updateProfitFields);
    $('#id_x2_unit_base, #id_x2_unit_add, #id_x2_unit_max').on('keyup change input', updateUnitRateFields);
    $('#id_x2_run').on('change', syncCompleteDatetime);

    syncCompleteDatetime();
    updateProfitFields();
    updateUnitRateFields();
});

function updateFileInfo(input, index) {
    if(input.files.length > 0) {
        document.getElementById('f_name_' + index).innerText = input.files[0].name;
        document.getElementById('f_name_' + index).style.color = "#00d4ff";
    }
}
function addFileSlot() {
    const $next = $('.file-box-custom:not(.active)').first();
    if ($next.length) {
        $next.addClass('active');
    }
}
function toggleExtraArea() {
    const area = $('#extra_area');
    const icon = $('#btn_extra_toggle i');
    if(area.is(':visible')) {
        area.removeClass('is-open').addClass('is-close').slideUp(250);
        icon.removeClass('fa-chevron-up').addClass('fa-chevron-down');
    } else {
        area.removeClass('is-close').addClass('is-open').slideDown(250);
        icon.removeClass('fa-chevron-down').addClass('fa-chevron-up');
    }
}
function fwrite_submit(f) {
    <?php echo $editor_js; ?>
    return true;
}
</script>