<commit_before>@inject BTCPayServer.Security.ContentSecurityPolicies csp 
@model PayButtonViewModel
@{
    ViewData.SetActivePage(StoreNavPages.PayButton, "Pay Button", Context.GetStoreData().Id);
    csp.AllowUnsafeHashes("onBTCPayFormSubmit(event);return false");
    csp.AllowUnsafeHashes("handleSliderChange(event);return false");
    csp.AllowUnsafeHashes("handleSliderInput(event);return false");
    csp.AllowUnsafeHashes("handlePriceSlider(event);return false");
    csp.AllowUnsafeHashes("handlePriceInput(event);return false");
    csp.AllowUnsafeHashes("handlePlusMinus(event);return false");
}

@section PageHeadContent {
    <link rel="stylesheet" href="~/vendor/highlightjs/default.min.css" asp-append-version="true">
}

@section PageFootContent {
    <script src="~/vendor/highlightjs/highlight.min.js" asp-append-version="true"></script>
    <script src="~/vendor/vuejs/vue.js" asp-append-version="true"></script>
    <script src="~/vendor/vuejs-vee-validate/vee-validate.js" asp-append-version="true"></script>
    <script src="~/vendor/clipboard.js/clipboard.js" asp-append-version="true"></script>
    <script src="~/paybutton/paybutton.js" asp-append-version="true"></script>
    <template id="template-modal" csp-allow>
    if (!window.btcpay) {
        var script = document.createElement('script');
        script.src = @(Safe.Json(Model.UrlRoot + "modal/btcpay.js"));
        document.getElementsByTagName('head')[0].append(script);
    }
    function onBTCPayFormSubmit(event) {
        event.preventDefault();
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200 && this.responseText) {
                window.btcpay.showInvoice(JSON.parse(this.responseText).invoiceId);
            }
        };
        xhttp.open('POST', event.target.getAttribute('action'), true);
        xhttp.send(new FormData(event.target));
    }
    </template>
    <template id="template-price-buttons" csp-allow>
    function handlePlusMinus(event) {
        event.preventDefault();
        const root = event.target.closest('.btcpay-form');
        const el = root.querySelector('.btcpay-input-price');
        const step = parseInt(event.target.dataset.step) || 1;
        const min = parseInt(event.target.dataset.min) || 1;
        const max = parseInt(event.target.dataset.max);
        const type = event.target.dataset.type;
        const price = parseInt(el.value) || min;
        if (type === '-') {
            el.value = price - step < min ? min : price - step;
        } else if (type === '+') {
            el.value = price + step > max ? max : price + step;
        }
    }
    </template>
    <template id="template-price-input" csp-allow>
    function handlePriceInput(event) {
        event.preventDefault();
        const root = event.target.closest('.btcpay-form');
        const price = parseInt(event.target.dataset.price);
        if (isNaN(event.target.value)) root.querySelector('.btcpay-input-price').value = price;
        const min = parseInt(event.target.getAttribute('min')) || 1;
        const max = parseInt(event.target.getAttribute('max'));
        if (event.target.value < min) {
            event.target.value = min;
        } else if (event.target.value > max) { 
            event.target.value = max;
        }
    }
    </template>
    <template id="template-price-slider" csp-allow>
    function handleSliderChange(event) {
        event.preventDefault();
        const root = event.target.closest('.btcpay-form');
        const el = root.querySelector('.btcpay-input-price');
        const price = parseInt(el.value);
        const min = parseInt(event.target.getAttribute('min')) || 1;
        const max = parseInt(event.target.getAttribute('max'));
        if (price < min) { 
            el.value = min;
        } else if (price > max) {
            el.value = max;
        } 
        root.querySelector('.btcpay-input-range').value = el.value;
    }
    
    function handleSliderInput(event) {
        event.target.closest('.btcpay-form').querySelector('.btcpay-input-price').value = event.target.value;
    }
    </template>
    
    
    <script>
        const srvModel = @Safe.Json(Model);
        const payButtonCtrl = new Vue({
            el: '#payButtonCtrl',
            data: {
                srvModel: srvModel,
                originalButtonImageUrl: srvModel.payButtonImageUrl,
                buttonInlineTextMode: false
            },
            computed: {
                imageUrlRequired() {
                    return !this.buttonInlineTextMode;
                }
            },
            methods: {
                inputChanges(event, buttonSize) {
                    inputChanges(event, buttonSize);
                }
            },
            watch: {
                buttonInlineTextMode(checked) {
                    if (!checked) {
                        this.srvModel.payButtonText = '';
                        this.srvModel.payButtonImageUrl = this.originalButtonImageUrl;
                    } else {
                        this.srvModel.payButtonText = 'Pay with';
                        this.srvModel.payButtonImageUrl = `${this.srvModel.urlRoot}img/logo.svg`;
                    }
                    this.inputChanges();
                }
            }
        });
    </script>
}

<partial name="_StatusMessage" />

<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<div id="payButtonCtrl">
    <div class="row">
        <div class="col-xl-8">
            <div class="alert alert-warning alert-dismissible mb-4" role="alert">
                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
                    <vc:icon symbol="close" />
                </button>
                <p><strong>Warning:</strong> This feature should not be activated on a BTCPay Server store processing commercial transactions.</p>
                <p>By activating this feature, a malicious user can trick you into thinking an order has been processed by creating a new invoice, reusing the same Order Id of another valid order but different amount or currency.</p>
                <p>If this store process commercial transactions, we advise you to <a asp-controller="UIUserStores" asp-action="CreateStore" class="alert-link">create a separate store</a> before using the payment button.</p>
                <form asp-action="DisableAnyoneCanCreateInvoice" asp-route-storeId="@Context.GetRouteValue("storeId")" method="post">
                    <button name="command" id="disable-pay-button" type="submit" class="btn btn-danger mt-0" value="Save">Disable payment button</button>
                </form>
            </div>
            <p>Configure your Pay Button, and the generated code will be displayed at the bottom of the page to copy into your project.</p>
            <h4 class="mt-3 mb-3">General Settings</h4>
            <div class="form-group col-md-8">
                <label class="form-label" for="price">Price</label>
                <input name="price" type="text" class="form-control" id="price" inputmode="decimal"
                       v-model="srvModel.price" v-on:change="inputChanges"
                       v-validate="'decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }">
                <small class="text-danger">{{ errors.first('price') }}</small>
            </div>
            <div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
                <label class="form-label" for="currency">Currency</label>
                <input asp-for="Currency" currency-selection class="form-control"/>
            </div>
            <div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
                <label class="form-label" for="defaultPaymentMethod">Default Payment Method</label>
                <select v-model="srvModel.defaultPaymentMethod" v-on:change="inputChanges" class="form-select" id="default-payment-method">
                    <option value="" selected>Use the store’s default</option>
                    <option  v-for="pm in srvModel.paymentMethods" v-bind:value="pm.value">{{pm.name}}</option>
                </select>
            </div>
            <div class="form-group" v-if="!srvModel.appIdEndpoint">
                <label class="form-label" for="description">Checkout Description</label>
                <input name="checkoutDesc" type="text" class="form-control" id="description"
                       v-model="srvModel.checkoutDesc" v-on:change="inputChanges">
            </div>
            <div class="form-group">
                <label class="form-label" for="order-id">Order ID</label>
                <input name="orderId" type="text" class="form-control" id="order-id"
                       v-model="srvModel.orderId" v-on:change="inputChanges">
            </div>
        </div>
    </div>

    <h4 class="mt-5 mb-3">Display Options</h4>
    <div class="row">
        <div class="col-xl-8 col-xxl-constrain">
            <div class="form-group">
                <div class="form-check" v-if="!srvModel.appIdEndpoint">
                    <input id="useModal" type="checkbox" v-model="srvModel.useModal" v-on:change="inputChanges" class="form-check-input"/>
                    <label for="useModal" class="form-check-label">Use Modal</label>
                </div>
                <div class="form-check">
                    <input id="buttonInlineTextMode" type="checkbox" v-model="buttonInlineTextMode" v-on:change="inputChanges" class="form-check-input"/><commit_msg>Pay Button: Re-add Vue handlers to currency input (#3646)<commit_after>@inject BTCPayServer.Security.ContentSecurityPolicies csp 
@model PayButtonViewModel
@{
    ViewData.SetActivePage(StoreNavPages.PayButton, "Pay Button", Context.GetStoreData().Id);
    csp.AllowUnsafeHashes("onBTCPayFormSubmit(event);return false");
    csp.AllowUnsafeHashes("handleSliderChange(event);return false");
    csp.AllowUnsafeHashes("handleSliderInput(event);return false");
    csp.AllowUnsafeHashes("handlePriceSlider(event);return false");
    csp.AllowUnsafeHashes("handlePriceInput(event);return false");
    csp.AllowUnsafeHashes("handlePlusMinus(event);return false");
}

@section PageHeadContent {
    <link rel="stylesheet" href="~/vendor/highlightjs/default.min.css" asp-append-version="true">
}

@section PageFootContent {
    <script src="~/vendor/highlightjs/highlight.min.js" asp-append-version="true"></script>
    <script src="~/vendor/vuejs/vue.js" asp-append-version="true"></script>
    <script src="~/vendor/vuejs-vee-validate/vee-validate.js" asp-append-version="true"></script>
    <script src="~/vendor/clipboard.js/clipboard.js" asp-append-version="true"></script>
    <script src="~/paybutton/paybutton.js" asp-append-version="true"></script>
    <template id="template-modal" csp-allow>
    if (!window.btcpay) {
        var script = document.createElement('script');
        script.src = @(Safe.Json(Model.UrlRoot + "modal/btcpay.js"));
        document.getElementsByTagName('head')[0].append(script);
    }
    function onBTCPayFormSubmit(event) {
        event.preventDefault();
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200 && this.responseText) {
                window.btcpay.showInvoice(JSON.parse(this.responseText).invoiceId);
            }
        };
        xhttp.open('POST', event.target.getAttribute('action'), true);
        xhttp.send(new FormData(event.target));
    }
    </template>
    <template id="template-price-buttons" csp-allow>
    function handlePlusMinus(event) {
        event.preventDefault();
        const root = event.target.closest('.btcpay-form');
        const el = root.querySelector('.btcpay-input-price');
        const step = parseInt(event.target.dataset.step) || 1;
        const min = parseInt(event.target.dataset.min) || 1;
        const max = parseInt(event.target.dataset.max);
        const type = event.target.dataset.type;
        const price = parseInt(el.value) || min;
        if (type === '-') {
            el.value = price - step < min ? min : price - step;
        } else if (type === '+') {
            el.value = price + step > max ? max : price + step;
        }
    }
    </template>
    <template id="template-price-input" csp-allow>
    function handlePriceInput(event) {
        event.preventDefault();
        const root = event.target.closest('.btcpay-form');
        const price = parseInt(event.target.dataset.price);
        if (isNaN(event.target.value)) root.querySelector('.btcpay-input-price').value = price;
        const min = parseInt(event.target.getAttribute('min')) || 1;
        const max = parseInt(event.target.getAttribute('max'));
        if (event.target.value < min) {
            event.target.value = min;
        } else if (event.target.value > max) { 
            event.target.value = max;
        }
    }
    </template>
    <template id="template-price-slider" csp-allow>
    function handleSliderChange(event) {
        event.preventDefault();
        const root = event.target.closest('.btcpay-form');
        const el = root.querySelector('.btcpay-input-price');
        const price = parseInt(el.value);
        const min = parseInt(event.target.getAttribute('min')) || 1;
        const max = parseInt(event.target.getAttribute('max'));
        if (price < min) { 
            el.value = min;
        } else if (price > max) {
            el.value = max;
        } 
        root.querySelector('.btcpay-input-range').value = el.value;
    }
    
    function handleSliderInput(event) {
        event.target.closest('.btcpay-form').querySelector('.btcpay-input-price').value = event.target.value;
    }
    </template>
    
    
    <script>
        const srvModel = @Safe.Json(Model);
        const payButtonCtrl = new Vue({
            el: '#payButtonCtrl',
            data: {
                srvModel: srvModel,
                originalButtonImageUrl: srvModel.payButtonImageUrl,
                buttonInlineTextMode: false
            },
            computed: {
                imageUrlRequired() {
                    return !this.buttonInlineTextMode;
                }
            },
            methods: {
                inputChanges(event, buttonSize) {
                    inputChanges(event, buttonSize);
                }
            },
            watch: {
                buttonInlineTextMode(checked) {
                    if (!checked) {
                        this.srvModel.payButtonText = '';
                        this.srvModel.payButtonImageUrl = this.originalButtonImageUrl;
                    } else {
                        this.srvModel.payButtonText = 'Pay with';
                        this.srvModel.payButtonImageUrl = `${this.srvModel.urlRoot}img/logo.svg`;
                    }
                    this.inputChanges();
                }
            }
        });
    </script>
}

<partial name="_StatusMessage" />

<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<div id="payButtonCtrl">
    <div class="row">
        <div class="col-xl-8">
            <div class="alert alert-warning alert-dismissible mb-4" role="alert">
                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
                    <vc:icon symbol="close" />
                </button>
                <p><strong>Warning:</strong> This feature should not be activated on a BTCPay Server store processing commercial transactions.</p>
                <p>By activating this feature, a malicious user can trick you into thinking an order has been processed by creating a new invoice, reusing the same Order Id of another valid order but different amount or currency.</p>
                <p>If this store process commercial transactions, we advise you to <a asp-controller="UIUserStores" asp-action="CreateStore" class="alert-link">create a separate store</a> before using the payment button.</p>
                <form asp-action="DisableAnyoneCanCreateInvoice" asp-route-storeId="@Context.GetRouteValue("storeId")" method="post">
                    <button name="command" id="disable-pay-button" type="submit" class="btn btn-danger mt-0" value="Save">Disable payment button</button>
                </form>
            </div>
            <p>Configure your Pay Button, and the generated code will be displayed at the bottom of the page to copy into your project.</p>
            <h4 class="mt-3 mb-3">General Settings</h4>
            <div class="form-group col-md-8">
                <label class="form-label" for="price">Price</label>
                <input name="price" type="text" class="form-control" id="price" inputmode="decimal"
                       v-model="srvModel.price" v-on:change="inputChanges"
                       v-validate="'decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }">
                <small class="text-danger">{{ errors.first('price') }}</small>
            </div>
            <div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
                <label class="form-label" for="Currency">Currency</label>
                <input asp-for="Currency" name="currency" currency-selection class="form-control"
                       v-model="srvModel.currency" v-on:change="inputChanges"
                       :class="{'is-invalid': errors.has('currency') }" />
            </div>
            <div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
                <label class="form-label" for="defaultPaymentMethod">Default Payment Method</label>
                <select v-model="srvModel.defaultPaymentMethod" v-on:change="inputChanges" class="form-select" id="default-payment-method">
                    <option value="" selected>Use the store’s default</option>
                    <option  v-for="pm in srvModel.paymentMethods" v-bind:value="pm.value">{{pm.name}}</option>
                </select>
            </div>
            <div class="form-group" v-if="!srvModel.appIdEndpoint">
                <label class="form-label" for="description">Checkout Description</label>
                <input name="checkoutDesc" type="text" class="form-control" id="description"
                       v-model="srvModel.checkoutDesc" v-on:change="inputChanges">
            </div>
            <div class="form-group">
                <label class="form-label" for="order-id">Order ID</label>
                <input name="orderId" type="text" class="form-control" id="order-id"
                       v-model="srvModel.orderId" v-on:change="inputChanges">
            </div>
        </div>
    </div>

    <h4 class="mt-5 mb-3">Display Options</h4>
    <div class="row">
        <div class="col-xl-8 col-xxl-constrain">
            <div class="form-group">
                <div class="form-check" v-if="!srvModel.appIdEndpoint">
                    <input id="useModal" type="checkbox" v-model="srvModel.useModal" v-on:change="inputChanges" class="form-check-input"/>
                    <label for="useModal" class="form-check-label">Use Modal</label>
                </div>
                <div class="form-check">
                    <input id="buttonInlineTextMode" type="checkbox" v-model="buttonInlineTextMode" v-on:change="inputChanges" class="form-check-input"/>
{'fraction_non_alphanumeric': 0.142620832256397, 'fraction_numerical': 0.003204962522615663, 'mean_word_length': 2.3378191856452726, 'pattern_counts': {'":': 0, '<': 201, '<?xml version=': 0, '>': 201, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2483855', 'n_tokens_mistral': 5546, 'n_tokens_neox': 5439, 'n_words': 1030}