<%@ Page Title="Parallel Chunks" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" %>
<%@ Register Assembly="AjaxUploader" Namespace="AjaxUploader.Controls" TagPrefix="au" %> 
<asp:Content ID="TitleContent" ContentPlaceHolderID="TitleContent" runat="server">Parallel Chunks - AjaxUploader v5.3 Demos</asp:Content>
<asp:Content ID="HeaderContent" ContentPlaceHolderID="HeaderTitle" runat="server">Parallel Chunks</asp:Content> 
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> 
<div class="demo-card"> <div class="demo-card-header">Parallel Chunk Uploads</div> <div class="demo-card-body"> <p class="demo-description"> Upload multiple chunks of a file simultaneously to maximize bandwidth utilization.
 The <code>ParallelChunks</code> setting controls how many chunk requests are sent in parallel.
 </p> <div class="demo-expect"><strong>What you should see:</strong> 3 chunks of 2&nbsp;MB in flight at once (adjustable). With a large file the network panel shows parallel chunk requests rather than a single queue.</div> <au:AjaxFileUpload ID="Uploader1" runat="server"
 EnableChunkedUpload="true"
 ChunkSize="2097152"
 ParallelChunks="3"
 AllowMultiple="true"
 ShowProgress="true" /> <div class="mb-3 mt-3"> <label class="form-label fw-bold" for="concurrency">Concurrency</label> <select id="concurrency" class="form-select" style="width:auto;display:inline-block;"> <option value="1">1 (Sequential)</option> <option value="2">2 Parallel</option> <option value="3" selected>3 Parallel</option> <option value="5">5 Parallel</option> </select> </div> <div id="stats" class="mt-2 text-muted small"></div> <div class="code-panel"> <pre><code>&lt;au:AjaxFileUpload ID="Uploader1" runat="server"
 EnableChunkedUpload="true"
 ChunkSize="2097152"
 ParallelChunks="3"
 AllowMultiple="true"
 ShowProgress="true" /&gt;

// JavaScript API approach
var uploader = AjaxUploader.create('#uploader', {
 uploadUrl: '<%= ResolveUrl("~/ajaxupload.axd/upload") %>',
 chunkUrl: '<%= ResolveUrl("~/ajaxupload.axd/chunk") %>',
 chunkCompleteUrl: '<%= ResolveUrl("~/ajaxupload.axd/chunk/complete") %>',
 chunked: true,
 chunkSize: 2 * 1024 * 1024,
 concurrency: 3, // parallel chunk uploads
 onTaskProgress: function(task) {
 stats.textContent = task.fileName + ': ' +
 clampPercent(task.percent) + '% - ' +
 AjaxUploader.formatSize(task.speed) + '/s';
 }
});</code></pre> </div> </div>
</div> 
</asp:Content> 
<asp:Content ID="ScriptsContent" ContentPlaceHolderID="ScriptsContent" runat="server">
<script> var stats = document.getElementById('stats');
 function setStats(message) {
 if (stats) stats.textContent = message;
 }
 function clampPercent(value) {
 var pct = Number(value);
 if (!isFinite(pct)) return 0;
 return Math.max(0, Math.min(100, Math.round(pct)));
 }
 var concurrency = document.getElementById('concurrency');
 var uploader = window.AjaxUploader && AjaxUploader.getInstance ? AjaxUploader.getInstance('Uploader1') : null;
 if (uploader) {
 uploader.on('taskProgress', function(task) {
 setStats(task.fileName + ': ' +
 clampPercent(task.percent) + '% - ' +
 AjaxUploader.formatSize(task.speed) + '/s');
 });
 uploader.on('taskComplete', function(task) {
 setStats(task.fileName + ' completed.');
 });
 } else {
 setStats('Uploader API is still loading. Refresh the page or try again in a moment.');
 }

 if (concurrency) concurrency.addEventListener('change', function() {
 if (uploader) {
 uploader.setOptions({ concurrency: parseInt(this.value) });
 }
 });
</script>
</asp:Content>
