<%@ Page Title="Sequential Queue" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" %>
<%@ Register Assembly="AjaxUploader" Namespace="AjaxUploader.Controls" TagPrefix="au" %> 
<asp:Content ID="TitleContent" ContentPlaceHolderID="TitleContent" runat="server">Sequential Queue - AjaxUploader v5.2 Demos</asp:Content>
<asp:Content ID="HeaderContent" ContentPlaceHolderID="HeaderTitle" runat="server">Sequential Queue</asp:Content> 
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> 
<div class="demo-card"> <div class="demo-card-header">Sequential File Upload Queue</div> <div class="demo-card-body"> <p class="demo-description"> <strong>Files upload one at a time in the order they were added.</strong> Each file waits for
 the previous upload to complete before starting - ideal when server resources are limited
 or downstream services rate-limit per connection. v5.2 queues are also <strong>drag-to-reorder</strong>;
 see <a href="QueueReordering.aspx">reorder demo</a>. For parallel transfers, see
 <a href="ConcurrentUploads.aspx">concurrent uploads</a>.
 </p> <div class="demo-expect"><strong>What you should see:</strong> strictly one file at a time: the next upload starts only when the previous finishes.</div> <au:AjaxFileUpload ID="Uploader1" runat="server"
 AllowMultiple="true"
 ConcurrentUploads="1"
 AutoUpload="true"
 ShowProgress="true" /> <div id="queueList" class="mt-3"></div> <div id="status" class="mt-2 text-muted small" role="status" aria-live="polite"></div> <div class="code-panel"> <pre><code>&lt;au:AjaxFileUpload ID="Uploader1" runat="server"
 AllowMultiple="true"
 ConcurrentUploads="1"
 AutoUpload="true"
 ShowProgress="true" /&gt;

// JavaScript API approach
AjaxUploader.create('#uploader', {
 uploadUrl: '<%= ResolveUrl("~/ajaxupload.axd/upload") %>',
 multiple: true,
 concurrency: 1, // one file at a time
 autoUpload: true,
 onQueueRender: function(queue) {
 // Render queue items showing order and status
 queue.forEach(function(item, i) {
 // item.fileName, item.status, item.percent
 });
 }
});</code></pre> </div> </div>
</div> 
</asp:Content> 
<asp:Content ID="ScriptsContent" ContentPlaceHolderID="ScriptsContent" runat="server">
<script> var queueList = document.getElementById('queueList');
 var status = document.getElementById('status');
 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 (!queueList || !status) return;
 queueList.textContent = '';
 queue.forEach(function(item, i) {
 var div = document.createElement('div');
 div.className = 'p-2 mb-1 border rounded d-flex justify-content-between align-items-center';
 var badge = item.status === 'complete' ? 'bg-success' :
 item.status === 'uploading' ? 'bg-primary' : 'bg-secondary';
 var info = document.createElement('span');
 info.appendChild(document.createTextNode((i + 1) + '. ' + item.fileName + ' '));
 var size = document.createElement('small');
 size.className = 'text-muted';
 size.textContent = '(' + (window.AjaxUploader && AjaxUploader.formatSize ? AjaxUploader.formatSize(item.total) : (item.total || 0) + ' B') + ')';
 info.appendChild(size);
 var statusBadge = document.createElement('span');
 statusBadge.className = 'badge ' + badge;
 statusBadge.textContent = item.status === 'uploading' ? clampPercent(item.percent) + '%' : item.status;
 div.appendChild(info);
 div.appendChild(statusBadge);
 queueList.appendChild(div);
 });
 status.textContent = queue.length + ' file(s) in queue';
 });
 uploader.on('complete', function() {
 if (!status) return;
 status.textContent = 'All uploads complete.';
 });
 }
</script>
</asp:Content>
