<%@ Page Title="Concurrent Uploads" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" %>
<%@ Register Assembly="AjaxUploader" Namespace="AjaxUploader.Controls" TagPrefix="au" %> 
<asp:Content ID="TitleContent" ContentPlaceHolderID="TitleContent" runat="server">Concurrent Uploads - AjaxUploader v5.2 Demos</asp:Content>
<asp:Content ID="HeaderContent" ContentPlaceHolderID="HeaderTitle" runat="server">Concurrent Uploads</asp:Content> 
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> 
<div class="demo-card"> <div class="demo-card-header">Parallel Upload Slots</div> <div class="demo-card-body"> <p class="demo-description"> Upload multiple files simultaneously with configurable concurrency. Three parallel upload
 slots allow faster overall completion while limiting server load.
 </p> <au:AjaxFileUpload ID="Uploader1" runat="server"
 AllowMultiple="true"
 ConcurrentUploads="3"
 AutoUpload="true"
 ShowProgress="true" /> <div class="mb-3 mt-3"> <div class="form-label fw-bold" id="uploadSlotsLabel">Upload Slots</div> <div class="btn-group" role="group" id="concurrencyControls" aria-labelledby="uploadSlotsLabel"> <button type="button" class="btn btn-outline-primary btn-sm" data-concurrency="1">1</button> <button type="button" class="btn btn-outline-primary btn-sm" data-concurrency="2">2</button> <button type="button" class="btn btn-outline-primary btn-sm active" data-concurrency="3">3</button> <button type="button" class="btn btn-outline-primary btn-sm" data-concurrency="5">5</button> </div> </div> <div id="slots" class="mt-3 d-flex gap-2 flex-wrap"></div> <div id="completed" class="mt-2 text-muted small"></div> <div class="code-panel"> <pre><code>&lt;au:AjaxFileUpload ID="Uploader1" runat="server"
 AllowMultiple="true"
 ConcurrentUploads="3"
 AutoUpload="true"
 ShowProgress="true" /&gt;

// JavaScript API approach
AjaxUploader.create('#uploader', {
 uploadUrl: '<%= ResolveUrl("~/ajaxupload.axd/upload") %>',
 multiple: true,
 maxFiles: 10,
 concurrency: 3, // 3 parallel upload slots
 autoUpload: true,
 onQueueRender: function(queue) {
 // Show active uploads in parallel slots
 }
});</code></pre> </div> </div>
</div> 
</asp:Content> 
<asp:Content ID="ScriptsContent" ContentPlaceHolderID="ScriptsContent" runat="server">
<script> var slots = document.getElementById('slots');
 var completed = document.getElementById('completed');
 var concurrencyControls = document.getElementById('concurrencyControls');
 var doneCount = 0;
 function clampPercent(value) {
 var pct = Number(value);
 if (!isFinite(pct)) return 0;
 return Math.max(0, Math.min(100, Math.round(pct)));
 }

 var uploader = window.AjaxUploader && typeof AjaxUploader.getInstance === 'function' ? AjaxUploader.getInstance('Uploader1') : null;
 if (uploader) {
 uploader.on('queueRender', function(queue) {
 if (!slots) return;
 slots.textContent = '';
 queue.forEach(function(item) {
 var card = document.createElement('div');
 card.className = 'border rounded p-2 text-center';
 card.style.cssText = 'min-width:140px;';
 var color = item.status === 'uploading' ? '#0d6efd' :
 item.status === 'complete' ? '#198754' : '#6c757d';
 var name = document.createElement('div');
 name.className = 'small text-truncate';
 name.style.maxWidth = '130px';
 name.textContent = item.fileName || 'File';
 var progress = document.createElement('div');
 progress.className = 'progress mt-1';
 progress.style.height = '6px';
 var bar = document.createElement('div');
 bar.className = 'progress-bar';
 var safePercent = clampPercent(item.percent);
 bar.style.width = safePercent + '%';
 bar.style.background = color;
 var status = document.createElement('div');
 status.className = 'small mt-1';
 status.style.color = color;
 status.textContent = item.status === 'uploading' ? safePercent + '%' : item.status;
 progress.appendChild(bar);
 card.appendChild(name);
 card.appendChild(progress);
 card.appendChild(status);
 slots.appendChild(card);
 });
 });
 uploader.on('taskComplete', function() {
 doneCount++;
 if (completed) completed.textContent = doneCount + ' file(s) completed.';
 });
 }

 function setConcurrency(n, button) {
 if (uploader && typeof uploader.setOptions === 'function') {
 uploader.setOptions({ concurrency: n });
 }
 if (!concurrencyControls || !button) return;
 concurrencyControls.querySelectorAll('.btn').forEach(function(b) { b.classList.remove('active'); });
 button.classList.add('active');
 }

 if (concurrencyControls) concurrencyControls.addEventListener('click', function(event) {
 var button = event.target.closest('button[data-concurrency]');
 if (!button || !concurrencyControls.contains(button)) {
 return;
 }
 setConcurrency(Number(button.dataset.concurrency), button);
 });
</script>
</asp:Content>
