<%@ Page Title="Custom Progress UI" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" %>
<%@ Register Assembly="AjaxUploader" Namespace="AjaxUploader.Controls" TagPrefix="au" %> 
<asp:Content ID="TitleContent" ContentPlaceHolderID="TitleContent" runat="server">Custom Progress UI - AjaxUploader v5.2 Demos</asp:Content>
<asp:Content ID="HeaderContent" ContentPlaceHolderID="HeaderTitle" runat="server">Custom Progress UI</asp:Content> 
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> 
<div class="demo-card"> <div class="demo-card-header">Fully Custom Progress Rendering</div> <div class="demo-card-body"> <p class="demo-description"> Build a completely custom progress display with file icon, name,
 size, progress bar, and action buttons rendered via JavaScript.
 </p> <div class="demo-expect"><strong>What you should see:</strong> a progress display built from your own markup, fed by the component's events - the built-in bar is unused.</div> <style> .custom-progress-list { margin-top: 1rem; }
 .cp-item {
 display: flex; align-items: center; gap: 0.75rem;
 padding: 0.6rem 0.75rem; margin-bottom: 0.5rem;
 border: 1px solid #e5e7eb; border-radius: 0.5rem;
 background: #fafafa;
 }
 .cp-icon { font-size: 1.4rem; }
 .cp-info { flex: 1; min-width: 0; }
 .cp-name { font-size: 0.85rem; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
 .cp-size { font-size: 0.7rem; color: #9ca3af; }
 .cp-bar { width: 100px; height: 6px; background: #e5e7eb; border-radius: 3px; overflow: hidden; }
 .cp-bar-fill { height: 100%; width: 0%; background: #3b82f6; transition: width 0.2s; }
 .cp-status { font-size: 0.75rem; width: 60px; text-align: right; }
 .cp-status.done { color: #10b981; font-weight: 600; }
 .cp-status.error { color: #ef4444; }
 </style> <div id="cpUploader"></div> <div class="custom-progress-list" id="cpList"></div> <div class="code-panel"> <pre><code>onTaskStart: function(task) {
 // build custom row: icon + name + size + bar + status
 list.appendChild(createCustomRow(task));
},
onTaskProgress: function(task, pct) {
 var safePct = clampPercent(pct);
 row.querySelector('.bar-fill').style.width = safePct + '%';
 row.querySelector('.status').textContent = safePct + '%';
},
onTaskComplete: function(task) {
 row.querySelector('.status').textContent = 'Done';
}</code></pre> </div> </div>
</div> 
</asp:Content> 
<asp:Content ID="ScriptsContent" ContentPlaceHolderID="ScriptsContent" runat="server">
<script> (function () {
 var list = document.getElementById('cpList');
 function clampPercent(value) {
 var pct = Number(value);
 if (!isFinite(pct)) return 0;
 return Math.max(0, Math.min(100, Math.round(pct)));
 }
 function fmtSize(b) {
 if (b >= 1048576) return (b / 1048576).toFixed(1) + ' MB';
 return (b / 1024).toFixed(0) + ' KB';
 }
 var uploaderHost = document.getElementById('cpUploader');
 if (window.AjaxUploader && typeof AjaxUploader.create === 'function' && uploaderHost) {
 AjaxUploader.create(uploaderHost, {
 uploadUrl: '<%= ResolveUrl("~/ajaxupload.axd/upload") %>',
 multiple: true,
 autoUpload: true,
 onTaskStart: function (task) {
 var el = document.createElement('div');
 el.className = 'cp-item'; el.id = 'cp-' + task.id;
 var icon = document.createElement('span');
 icon.className = 'cp-icon';
 var info = document.createElement('div');
 info.className = 'cp-info';
 var name = document.createElement('div');
 name.className = 'cp-name';
 name.textContent = task.fileName;
 var size = document.createElement('div');
 size.className = 'cp-size';
 size.textContent = fmtSize(task.fileSize || 0);
 info.appendChild(name);
 info.appendChild(size);
 var bar = document.createElement('div');
 bar.className = 'cp-bar';
 var fill = document.createElement('div');
 fill.className = 'cp-bar-fill';
 bar.appendChild(fill);
 var status = document.createElement('span');
 status.className = 'cp-status';
 status.textContent = '0%';
 el.appendChild(icon);
 el.appendChild(info);
 el.appendChild(bar);
 el.appendChild(status);
 if (!list) return;
 list.appendChild(el);
 },
 onTaskProgress: function (task, pct) {
 var el = document.getElementById('cp-' + task.id);
 if (!el) return;
 var safePct = clampPercent(pct);
 var fill = el.querySelector('.cp-bar-fill');
 var status = el.querySelector('.cp-status');
 if (fill) {
 fill.style.width = safePct + '%';
 }
 if (status) {
 status.textContent = safePct + '%';
 }
 },
 onTaskComplete: function (task) {
 var el = document.getElementById('cp-' + task.id);
 if (!el) return;
 var fill = el.querySelector('.cp-bar-fill');
 if (fill) {
 fill.style.width = '100%';
 fill.style.background = '#10b981';
 }
 var s = el.querySelector('.cp-status');
 if (!s) return;
 s.textContent = 'Done'; s.className = 'cp-status done';
 },
 onTaskError: function (task, err) {
 var el = document.getElementById('cp-' + task.id);
 if (!el) return;
 var s = el.querySelector('.cp-status');
 if (!s) return;
 s.textContent = 'Error'; s.className = 'cp-status error';
 }
 });
 }
 })();
</script>
</asp:Content>
