添加项目文件。

This commit is contained in:
Jackson.Bruce
2019-08-19 19:00:14 +08:00
parent 11f329b81e
commit edc9404a2a
41 changed files with 16172 additions and 0 deletions

View File

@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.779
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HTML5UploaderWebSiteTest", "Uploader\HTML5UploaderWebSiteTest.csproj", "{152482F9-A932-4C5A-914F-F7D646921286}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Html5Uploader", "Html5Uploader\Html5Uploader.csproj", "{07F2A054-679A-4AA7-8C78-DAFEBF6D2EEF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helper", "Helper\Helper.csproj", "{6C6C0829-DFB5-4AE1-B763-7803D23E17E9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{152482F9-A932-4C5A-914F-F7D646921286}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{152482F9-A932-4C5A-914F-F7D646921286}.Debug|Any CPU.Build.0 = Debug|Any CPU
{152482F9-A932-4C5A-914F-F7D646921286}.Release|Any CPU.ActiveCfg = Release|Any CPU
{152482F9-A932-4C5A-914F-F7D646921286}.Release|Any CPU.Build.0 = Release|Any CPU
{07F2A054-679A-4AA7-8C78-DAFEBF6D2EEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07F2A054-679A-4AA7-8C78-DAFEBF6D2EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07F2A054-679A-4AA7-8C78-DAFEBF6D2EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07F2A054-679A-4AA7-8C78-DAFEBF6D2EEF}.Release|Any CPU.Build.0 = Release|Any CPU
{6C6C0829-DFB5-4AE1-B763-7803D23E17E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C6C0829-DFB5-4AE1-B763-7803D23E17E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C6C0829-DFB5-4AE1-B763-7803D23E17E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C6C0829-DFB5-4AE1-B763-7803D23E17E9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DA7133B8-5E86-492C-8818-3DD6EC8C94D0}
EndGlobalSection
EndGlobal

134
Helper/Convert.cs Normal file
View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Helper
{
public class ConvertHelper
{
/// <summary>
/// 将数组转换为字符串
/// </summary>
/// <param name="arr"></param>
/// <returns></returns>
public static string ConvertToStringFromIntArray(IEnumerable<int> arr)
{
return ConvertToStringFromIntArray(arr, true, "");
}
/// <summary>
/// 将数组转换为字符串
/// </summary>
/// <param name="arr"></param>
/// <param name="IgnoreZero">是否匆略数组中的零值</param>
/// <returns></returns>
public static string ConvertToStringFromIntArray(IEnumerable<int> arr, bool IgnoreZero)
{
return ConvertToStringFromIntArray(arr, IgnoreZero, "");
}
/// <summary>
/// 将数组转换为字符串
/// </summary>
/// <param name="arr"></param>
/// <param name="IgnoreZero">是否匆略数组中的零值</param>
/// <param name="SpaceTag">指定个间隔字符串</param>
/// <returns></returns>
public static string ConvertToStringFromIntArray(IEnumerable<int> arr, bool IgnoreZero, string SpaceTag)
{
if (arr == null) return "";
if (string.IsNullOrEmpty(SpaceTag))
{
SpaceTag = ",";
}
StringBuilder sb = new StringBuilder();
foreach (int i in arr)
{
if (i == 0 && IgnoreZero) continue;
if (sb.Length > 0)
{
sb.Append(SpaceTag + i.ToString());
}
else
{
sb.Append(i.ToString());
}
}
return sb.ToString();
}
/// <summary>
/// 字符串转换为整型数组
/// </summary>
/// <param name="src"></param>
/// <returns></returns>
public static IEnumerable<int> ConvertToIntArrayFromString(string src)
{
return ConvertToIntArrayFromString(src, true, "");
}
/// <summary>
/// 字符串转换为整型数组
/// </summary>
/// <param name="src"></param>
/// <param name="IgnoreZero">是否匆略字符串中的零值</param>
/// <returns></returns>
public static IEnumerable<int> ConvertToIntArrayFromString(string src, bool IgnoreZero)
{
return ConvertToIntArrayFromString(src, IgnoreZero, "");
}
/// <summary>
/// 字符串转换为整型数组
/// </summary>
/// <param name="src"></param>
/// <param name="IgnoreZero">是否匆略字符串中的零值</param>
/// <param name="SpaceTag">指定字符串中的间隔字符串</param>
/// <returns></returns>
public static IEnumerable<int> ConvertToIntArrayFromString(string src, bool IgnoreZero, string SpaceTag)
{
if (string.IsNullOrEmpty(src)) return null;
if (string.IsNullOrEmpty(SpaceTag))
{
SpaceTag = ",";
}
string[] arr = src.Split(new string[] { SpaceTag }, StringSplitOptions.RemoveEmptyEntries);
List<int> list = new List<int>();
foreach (string i in arr)
{
int temp = 0;
if (Int32.TryParse(i, out temp))
{
if (temp == 0 && IgnoreZero) continue;
list.Add(temp);
}
}
return list;
}
/// <summary>
/// 返回一个以逗号隔的ID列表
/// 如果参数ListId为空或所有元数为0则抛出ArgumentException异常
/// </summary>
/// <param name="ListId"></param>
/// <returns></returns>
public static string ValidateListId(IEnumerable<int> ListId)
{
string IdStr = ConvertToStringFromIntArray(ListId);
if (string.IsNullOrEmpty(IdStr) || IdStr.Trim()=="")
{
throw new ArgumentException("至少要指定一个ID");
}
return IdStr;
}
/// <summary>
/// 转换到客户端字符串,将”"\n,\r“转换为客户端的转义字符
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ConvertToClientString(string s)
{
return (s ?? "").Trim().Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n").Replace("\r", "\\r");
}
}
}

138
Helper/Helper.csproj Normal file
View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6C6C0829-DFB5-4AE1-B763-7803D23E17E9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>System.Helper</RootNamespace>
<AssemblyName>Helper</AssemblyName>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<IsWebBootstrapper>true</IsWebBootstrapper>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<SignAssembly>false</SignAssembly>
<AssemblyOriginatorKeyFile>Jackson.pfx</AssemblyOriginatorKeyFile>
<PublishUrl>http://localhost/Helper/</PublishUrl>
<Install>true</Install>
<InstallFrom>Web</InstallFrom>
<UpdateEnabled>true</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="HtmlAgilityPack">
<HintPath>L:\学习\编程类\C#\DLL\html解析器\HtmlAgilityPack.1.4.6\Net40\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.Entity">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.Entity.Design">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="XmlLinqExtensionMethods.cs" />
<Compile Include="Convert.cs" />
<Compile Include="Text.cs" />
<Compile Include="PatulousMethods.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Url.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
<Visible>False</Visible>
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
<Visible>False</Visible>
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<None Include="Jackson.pfx" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

15
Helper/PatulousMethods.cs Normal file
View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace System.Helper
{
public static class PatulousMethods
{
public static bool IsNumber(this string s)
{
return Regex.IsMatch(s, @"\d+");
}
}
}

View File

@@ -0,0 +1,41 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
[assembly: AllowPartiallyTrustedCallers()]
// 有关程序集的常规信息通过下列属性集
// 控制。更改这些属性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Helper")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("dog star")]
[assembly: AssemblyProduct("Helper")]
[assembly: AssemblyCopyright("版权所有 (C) dog star 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 属性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("9550217a-5d51-4bea-adbf-30b3fec86865")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 内部版本号
// 修订号
//
// 可以指定所有这些值,也可以使用“修订号”和“内部版本号”的默认值,
// 方法是按如下所示使用“*”:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile(@"..\..\Jackson.pfx")]
//[assembly: AssemblyKeyName("")]
//[assembly: System.Security.AllowPartiallyTrustedCallers]

196
Helper/Text.cs Normal file
View File

@@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;
using System.Xml;
using System.Web;
namespace System.Helper
{
public class Text
{
/// <summary>
/// 截取指定长度的HTML
/// </summary>
/// <param name="html">被截取的HTML代码</param>
/// <param name="textMaxLength">指定的长度</param>
/// <param name="tags">要过滤的标签名称,例如:div </param>
/// <returns>返回被截取后的html代码</returns>
public static string InterceptHtml(string html, int textMaxLength, params string[] tags)
{
int o;
return InterceptHtml(html, textMaxLength, out o, tags);
}
/// <summary>
/// 截取指定长度的HTML
/// </summary>
/// <param name="html">被截取的HTML代码</param>
/// <param name="textMaxLength">指定的长度</param>
/// <param name="residualCount">输出剩余的数量</param>
/// <param name="tags">要过滤的标签名称,例如:div </param>
/// <returns>返回被截取后的html代码</returns>
public static string InterceptHtml(string html, int textMaxLength, out int residualCount
,params string[] tags )
{
residualCount = 0;
if (string.IsNullOrEmpty(html) || html.Trim() == "")
{ return html; }
string str = "";
html = FilterTag(html, tags);
XmlDocument doc = new XmlDocument();
doc.LoadXml("<root></root>");
XmlNode n = doc.DocumentElement;
n.InnerXml = html;
int len = 0;
residualCount = n.InnerText.Length - textMaxLength;
if (residualCount < 0) residualCount = 0;
if (n.HasChildNodes)
{
XmlNodeList ns = GetNodes(n);
foreach (XmlNode t in ns)
{
if (t.InnerText.Trim() == "")
{
str += t.OuterXml;
continue;
}
if (t.InnerText.Trim().Length <= textMaxLength - len)
{
str += t.OuterXml;
len += t.InnerText.Trim().Length;
}
else
{
if (t.NodeType == XmlNodeType.Text || (t.HasChildNodes && t.ChildNodes.Count == 1 && t.ChildNodes[0].NodeType == XmlNodeType.Text))
{
string text = t.InnerText.Trim();
len = textMaxLength - len;
text = text.Length > len ? text.Substring(0, len) : text;
t.InnerText = text;
str += t.OuterXml;
}
else
{
t.InnerXml = InterceptHtml(t.InnerXml, textMaxLength - len);
str += t.OuterXml;
}
break; ;
}
if (len >= textMaxLength)
{ break; }
}
}
else
{
string text = n.InnerText.Trim();
text = text.Length > textMaxLength ? text.Substring(0, textMaxLength) : text;
n.InnerText = text;
str = n.OuterXml;
}
return str;
}
public static string Replace(string html, Regex rgx, MatchEvaluator evaluator)
{
if (string.IsNullOrEmpty(html) || html.Trim() == "")
{ return html; }
html = FilterTag(html, null);
XmlDocument doc = new XmlDocument();
doc.LoadXml("<root></root>");
XmlNode n = doc.DocumentElement;
n.InnerXml = html;
Replace(n, rgx, evaluator);
return n.InnerXml;
}
private static void Replace(XmlNode n, Regex rgx, MatchEvaluator evaluator)
{
if (n.HasChildNodes)
{
XmlNodeList ns = GetNodes(n);
foreach (XmlNode t in ns)
{
if (t.NodeType == XmlNodeType.Text)
{
if (t.InnerText.Trim() == "")
{
continue;
}
t.InnerText = rgx.Replace(t.InnerText, evaluator);
}
else if(t.HasChildNodes){
Replace(t, rgx, evaluator);
}
}
}
else
{
if (n.NodeType == XmlNodeType.Text)
{
if (n.InnerText.Trim() != "")
{
n.InnerText = rgx.Replace(n.InnerText, evaluator);
}
}
}
}
private static XmlNodeList GetNodes(XmlNode e)
{
return e.ChildNodes;
}
private static string FilterTag(string htm, string[] tags)
{
Regex r;
r = new Regex(@"</?\w+:\w+[^>]*>", RegexOptions.IgnoreCase);
htm = r.Replace(htm, "");
r = new Regex(@"<(\W)");
htm = r.Replace(htm, m => m.Success && m.Groups[1].Value!="/" ? HttpUtility.HtmlEncode(m.Value) : m.Value);
if (tags == null || tags.Length == 0)
return htm;
foreach (string t in tags)
{
r = new Regex(@"</?" + t + "[^>]*>", RegexOptions.IgnoreCase);
htm = r.Replace(htm, "");
}
return htm;
}
/// <summary>
/// 截取指定长度的文本
/// </summary>
/// <param name="text">原文本</param>
/// <param name="textMaxLength">最大长度</param>
/// <returns></returns>
public static string InterceptText(string text, int textMaxLength)
{
if (string.IsNullOrEmpty(text) || text.Length <= textMaxLength) return text ?? "";
return text.Substring(0, textMaxLength) + "...";
}
public static string Default(object text, params string[] DefaultValues)
{
return Default(text as string, DefaultValues);
}
public static string Default(string text,params string[] DefaultValues)
{
if (DefaultValues == null || DefaultValues.Length <= 0) return text;
var v = text;int i = 0;
while (string.IsNullOrWhiteSpace(v) && i < DefaultValues.Length)
{
v = DefaultValues[i];
i++;
}
return v;
}
public static string Trim(string text)
{
return string.IsNullOrWhiteSpace(text) ? string.Empty : text.Trim();
}
}
}

28
Helper/Url.cs Normal file
View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.IO;
using System.Web;
namespace System.Helper
{
public class Url
{
public static string GetRelativePath(string path)
{
Image img = new Image();
img.ImageUrl = path;
StringWriter sw = new StringWriter();
HtmlTextWriter writer = new HtmlTextWriter(sw);
img.RenderControl(writer);
Regex rgx = new Regex(@"src=""([^\""]+)""", RegexOptions.IgnoreCase);
Match m = rgx.Match(sw.ToString());
if (!m.Success)
{ return path; }
return m.Groups[1].Value;
}
}
}

View File

@@ -0,0 +1,387 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using HtmlAgilityPack;
namespace System.Xml.Linq
{
public static class XmlLinqExtensionMethods
{
public static XElement Attr(this XElement e, string name, object value)
{
if (e == null||string.IsNullOrEmpty(name)) return e;
XAttribute attr = e.Attribute(name);
if (attr == null)
{
if (value != null)
{
e.Add(new XAttribute(name, value));
}
}
else {
if (value == null) {
attr.Remove();
}
else
{
attr.Value = Convert.ToString(value);
}
}
return e;
}
public static string Attr(this XElement e, string name)
{
XAttribute attr = e == null || string.IsNullOrEmpty(name) ? null : e.Attribute(name);
return attr == null ? string.Empty : HttpUtility.HtmlDecode(attr.Value);
}
public static T Attr<T>(this XElement e, string name) where T : struct
{
return e.AttrStruct<T>(name, default(T));
}
public static T AttrStruct<T>(this XElement e, string name, T defaultValue = default(T)) where T : struct
{
string v = e.Attr(name);
if (string.IsNullOrWhiteSpace(v)) return defaultValue;
Type t = typeof(T);
try
{
if (t.IsEnum)
{
return (T)Enum.Parse(t, v);
}
else
{
return (T)Convert.ChangeType(v, t);
}
}
catch {
if (t == typeof(Guid))
{
object o = new Guid(v);
return (T)o;
}
}
return defaultValue;
}
public static string Attr(this HtmlNode e, string name)
{
var attr = e == null || !e.HasAttributes || string.IsNullOrEmpty(name) ? null : e.Attributes[name];
return attr == null ? string.Empty : HttpUtility.HtmlDecode(attr.Value);
}
public static T Attr<T>(this HtmlNode e, string name) where T : struct
{
return e.AttrStruct<T>(name, default(T));
}
public static T AttrStruct<T>(this HtmlNode e, string name, T defaultValue = default(T)) where T : struct
{
string v = e.Attr(name);
if (string.IsNullOrWhiteSpace(v)) return defaultValue;
Type t = typeof(T);
try
{
if (t.IsEnum)
{
return (T)Enum.Parse(t, v);
}
else
{
return (T)Convert.ChangeType(v, t);
}
}
catch
{
if (t == typeof(Guid))
{
object o = new Guid(v);
return (T)o;
}
}
return defaultValue;
}
public static string Text(this HtmlNode e)
{
return e != null ? e.InnerText : string.Empty;
}
public static string Html(this HtmlNode e)
{
return e != null ? e.InnerHtml : string.Empty;
}
public static bool HasClass(this HtmlNode node,string className)
{
string es = Regex.Escape(className);
var rgx = new Regex(@"(\s+" + es + @"\s*$)|(^\s*" + es + @"\s+)|(\s+" + es + @"\s+)");
var v = node.Attr("class").Trim();
return v != "" && (v == className || rgx.IsMatch(v));
}
public static HtmlNode GetNodeByClasName(this HtmlNode node, string className)
{
if (!node.HasChildNodes) return null;
var nodes = node.ChildNodes;
foreach (var item in nodes)
{
if (item.NodeType != HtmlNodeType.Element) continue;
if (item.HasClass(className))
{
return item;
}
var o = item.GetNodeByClasName(className);
if (o != null) return o;
}
return null;
}
public static HtmlNode GetNodeByTagName(this HtmlNode node, string tagName)
{
if (!node.HasChildNodes||string.IsNullOrWhiteSpace(tagName)) return null;
var nodes = node.ChildNodes;
foreach (var item in nodes)
{
if (item.NodeType != HtmlNodeType.Element) continue;
if (string.Equals(tagName,item.Name, StringComparison.OrdinalIgnoreCase))
{
return item;
}
var o = item.GetNodeByTagName(tagName);
if (o != null) return o;
}
return null;
}
public static HtmlNode GetNodeById(this HtmlNode node, string id)
{
if (!node.HasChildNodes || string.IsNullOrWhiteSpace(id)) return null;
var nodes = node.ChildNodes;
foreach (var item in nodes)
{
if (item.NodeType != HtmlNodeType.Element) continue;
if (string.Equals(id, item.Attr("id"), StringComparison.OrdinalIgnoreCase))
{
return item;
}
var o = item.GetNodeById(id);
if (o != null) return o;
}
return null;
}
public static IEnumerable<HtmlNode> GetNodesByClasName(this HtmlNode node, string className)
{
if (!node.HasChildNodes) return null;
var nodes = node.ChildNodes;
var list = new List<HtmlNode>();
foreach (var item in nodes)
{
if (item.NodeType != HtmlNodeType.Element) continue;
if (item.HasClass(className))
{
list.Add(item);
}
list.AddRange(item.GetNodesByClasName(className));
}
return list;
}
public static IEnumerable<HtmlNode> GetNodesByTagName(this HtmlNode node, string tagName)
{
if (!node.HasChildNodes || string.IsNullOrWhiteSpace(tagName)) return null;
var nodes = node.ChildNodes;
var list = new List<HtmlNode>();
foreach (var item in nodes)
{
if (item.NodeType != HtmlNodeType.Element) continue;
if (string.Equals(tagName, item.Name, StringComparison.OrdinalIgnoreCase))
{
list.Add(item);
}
list.AddRange(item.GetNodesByTagName(tagName));
}
return list;
}
public static IEnumerable<HtmlNode> AncestorNodes(this HtmlNode node)
{
var n = node;
do {
if (n != null)
{
n = n.ParentNode;
if (n != null && n.NodeType== HtmlNodeType.Element) yield return n;
}
} while (n != null);
}
public static bool Is(this HtmlNode node, string[] selectors)
{
if (node == null || node.NodeType != HtmlNodeType.Element || selectors == null || selectors.Length == 0) return false;
return selectors.Where(s => node.Is(s)).Any();
}
static bool IsMatch(HtmlNode e, string s)
{
var tagRgx = new Regex(@"^\w+", RegexOptions.IgnoreCase);
var classRgx = new Regex(@"\.[a-zA-Z_\-]+");
var idRgx = new Regex(@"#[a-zA-Z_\-]+");
var css = e.Attr("class");
var tagMatch = tagRgx.Match(s);
var idMatch = idRgx.Match(s);
var classMatches = classRgx.Matches(s);
var matched = (tagMatch == null || !tagMatch.Success || string.Equals(tagMatch.Value, e.Name, StringComparison.OrdinalIgnoreCase))
&& (idMatch == null || !idMatch.Success || string.Equals(idMatch.Value.TrimStart('#'), e.Attr("id"), StringComparison.Ordinal))
&& (classMatches == null || classMatches.Count == 0 || (
from n in classMatches.OfType<Match>()
join c in css.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(o => "." + o)
on n.Value equals c
select c
).Count() == classMatches.Count);
return matched;
}
public static bool Is(this HtmlNode node, string selector)
{
if(node==null || node.NodeType!= HtmlNodeType.Element || string.IsNullOrWhiteSpace(selector)) return false;
//string[] arr = selector.Split(new char[] { ' ' },StringSplitOptions.RemoveEmptyEntries).Reverse().ToArray();
selector = Regex.Replace(selector, @"\s*\>\s*", ">");
Func<string, Tuple<string[], bool>> lastSplit = s => {
int i1 = s.LastIndexOf('>'), i2 = s.LastIndexOf(' ');
if (i1 < 0 && i2 < 0)
{
return null;
}
else
{
int i = Math.Max(i1, i2);
return new Tuple<string[], bool>(new string[] { s.Substring(i + 1).Trim(), s.Substring(0, i).Trim() }, i1 > 0 && i1 > i2);
}
};
var current = node;
string sltrs = selector;
do
{
var tu = lastSplit(sltrs);
string sltr;
if (tu == null)
{
sltr = sltrs;
sltrs = null;
}
else {
sltr = tu.Item1[0];
sltrs = tu.Item1[1];
}
var m = IsMatch(current,sltr);
if (!m) return false;
if (tu != null && !tu.Item2)
{
bool nearMatched = false;
tu = lastSplit(sltrs);
sltr = tu == null ? sltrs : tu.Item1[0];
foreach (var e in current.AncestorNodes())
{
nearMatched = IsMatch(e, sltr);
if (nearMatched)
{
current = e.ParentNode;
sltrs = tu == null ? null : tu.Item1[1];
break;
}
}
if (!nearMatched) return false;
}
else {
current = current.ParentNode;
}
} while (sltrs != null);
return true;
}
public static IEnumerable<HtmlNode> GetNodes(this HtmlNode node, string selectors)
{
return string.IsNullOrWhiteSpace(selectors) ? node.Descendants() : from n in node.Descendants()
where n.Is(selectors.Split(','))
select n;
}
public static IEnumerable<HtmlNode> Before(this HtmlNode node, Func<HtmlNode, bool> assert=null)
{
var n =node==null?null: node.PreviousSibling;
do {
if (n != null)
{
if (assert == null || assert(n)) yield return n;
n = n.PreviousSibling;
}
}
while (n != null);
}
public static IEnumerable<HtmlNode> Behind(this HtmlNode node, Func<HtmlNode, bool> assert = null)
{
var n = node == null ? null : node.NextSibling;
do
{
if (n != null)
{
if (assert == null || assert(n)) yield return n;
n = n.NextSibling;
}
}
while (n != null);
}
public static HtmlNode Prev(this HtmlNode node)
{
do
{
node = node != null ? node.PreviousSibling : null;
} while (node != null && node.NodeType != HtmlNodeType.Element);
return node;
}
public static HtmlNode Next(this HtmlNode node)
{
do
{
node = node != null ? node.NextSibling : null;
} while (node != null && node.NodeType != HtmlNodeType.Element);
return node;
}
public static HtmlNode First(this IEnumerable<HtmlNode> nodes, string tagName = null)
{
if (nodes == null) return null;
return string.IsNullOrWhiteSpace(tagName) ? nodes.FirstOrDefault()
: (from n in nodes
where n.NodeType == HtmlNodeType.Element && string.Equals(n.Name, tagName, StringComparison.OrdinalIgnoreCase)
select n).FirstOrDefault();
}
public static HtmlNode First(this HtmlNodeCollection nodes, string tagName = null)
{
if (nodes == null || nodes.Count == 0) return null;
return nodes.Cast<HtmlNode>().First(tagName);
}
public static HtmlNode Last(this IEnumerable<HtmlNode> nodes, string tagName = null)
{
if (nodes == null) return null;
return string.IsNullOrWhiteSpace(tagName) ? nodes.LastOrDefault()
: (from n in nodes
where n.NodeType == HtmlNodeType.Element && string.Equals(n.Name, tagName, StringComparison.OrdinalIgnoreCase)
select n).LastOrDefault();
}
public static HtmlNode Last(this HtmlNodeCollection nodes,string tagName=null)
{
if (nodes == null || nodes.Count == 0) return null;
return nodes.Cast<HtmlNode>().Last(tagName);
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Html5Uploader.Controls
{
public class ClientEventsCollection : List<ClientEvent>
{
public ClientEvent this[ClientEventsNames name]
{
get
{
return this.Find(p => p.EventName == name);
}
set
{
ClientEvent par = this[name];
if (par == null)
{
par.EventName = value.EventName;
par.Handle = value.Handle;
}
else { Add(value); }
}
}
}
public class ClientEvent
{
public ClientEvent() { }
public ClientEvent(ClientEventsNames n, string v)
{ EventName = n; Handle = v; }
public ClientEventsNames EventName { get; set; }
public string Handle { get; set; }
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Html5Uploader.Controls
{
public enum SettingsNames
{
placeholder
,
multiple
,
accept
,
types
,
timeout
,
maxQueue
,
dragable
,
dragContainer
,
progress
,
blobSize
,
sliced
,
limitSize
,
url
,
parseResult
}
public enum ClientEventsNames
{
selecting
,
validate
,
selected
,
upload
,
createProgress
,
getResumableInfoHandler
,
progress
,
complete
,
success
,
error
,
cancel
,
proceed
,
pause
,
drop
,
dragover
,
dragleave
}
public enum UploaderSliceds
{
Auto = 0, Enabled = 1, Disabled = 2
}
}

View File

@@ -0,0 +1,410 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Helper;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Configuration;
using System.Web.UI;
using System.Web.UI.HtmlControls;
namespace Html5Uploader.Controls
{
[ParseChildren(true)]
[PersistChildren(false)]
[ToolboxData("<{0}:Html5UploaderClient runat=server></{0}:Html5UploaderClient>")]
public class Html5UploaderClient : Control, INamingContainer
{
Dictionary<SettingsNames, object> settings;
public Html5UploaderClient()
{
settings = new Dictionary<SettingsNames, object>();
RegisterScript = true;
}
private ITemplate _viewTemplate;
[DefaultValue("视图模板")]
[TemplateContainer(typeof(ViewTemplate))]
[PersistenceMode(PersistenceMode.InnerProperty)]
[Browsable(false)]
public ITemplate ViewTemplate
{
get { return _viewTemplate; }
set { _viewTemplate = value; }
}
[Description("客户端事件")]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ClientEventsCollection ClientEvents
{ get; set; }
[Description("随文件一起提交的参数列表")]
[PersistenceMode(PersistenceMode.InnerProperty)]
public PostParametersCollection PostParameters
{ get; set; }
[Description("服务端处理程序")]
[UrlProperty]
public string Url
{
get
{
return settings.ContainsKey(SettingsNames.url) ? settings[SettingsNames.url] as string : null;
}
set
{
settings[SettingsNames.url] = value;
}
}
string _token;
public string Token {
get { return _token; }
set {
if (value == null || value.Length <= 50)
{ _token = value; }
else { throw new Exception("Token的长度不能超过50个字符。"); }
}
}
public string Placeholder
{
get
{
return settings.ContainsKey(SettingsNames.placeholder) ? settings[SettingsNames.placeholder] as string : null;
}
set
{
settings[SettingsNames.placeholder] = value;
}
}
public bool Multiple
{
get
{
return settings.ContainsKey(SettingsNames.multiple) ? (bool)settings[SettingsNames.multiple] : true;
}
set
{
settings[SettingsNames.multiple] = value;
}
}
public string Accept
{
get
{
return settings.ContainsKey(SettingsNames.accept) ? settings[SettingsNames.accept] as string : null;
}
set
{
settings[SettingsNames.accept] = value;
}
}
public string Types
{
get
{
return settings.ContainsKey(SettingsNames.types) ? settings[SettingsNames.types] as string : null;
}
set
{
settings[SettingsNames.types] = value;
}
}
public string Timeout
{
get
{
return settings.ContainsKey(SettingsNames.timeout) ? settings[SettingsNames.timeout] as string : null;
}
set
{
settings[SettingsNames.timeout] = value;
}
}
public int MaxQueue
{
get
{
return settings.ContainsKey(SettingsNames.maxQueue) ? (int)settings[SettingsNames.maxQueue] : 2;
}
set
{
settings[SettingsNames.maxQueue] = value;
}
}
public bool Dragable
{
get
{
return settings.ContainsKey(SettingsNames.dragable) ? (bool)settings[SettingsNames.dragable] : true;
}
set
{
settings[SettingsNames.dragable] = value;
}
}
public string DragContainer
{
get
{
return settings.ContainsKey(SettingsNames.dragContainer) ? settings[SettingsNames.dragContainer] as string : null;
}
set
{
settings[SettingsNames.dragContainer] = value;
}
}
public string Progress
{
get
{
return settings.ContainsKey(SettingsNames.progress) ? settings[SettingsNames.progress] as string : null;
}
set
{
settings[SettingsNames.progress] = value;
}
}
public string BlobSize
{
get
{
return settings.ContainsKey(SettingsNames.blobSize) ? settings[SettingsNames.blobSize] as string : null;
}
set
{
settings[SettingsNames.blobSize] = value;
}
}
public UploaderSliceds Sliced
{
get
{
return settings.ContainsKey(SettingsNames.sliced) ? (UploaderSliceds)settings[SettingsNames.sliced] : UploaderSliceds.Auto;
}
set
{
settings[SettingsNames.sliced] = value;
}
}
public string LimitSize
{
get
{
return settings.ContainsKey(SettingsNames.limitSize) ? settings[SettingsNames.limitSize] as string : null;
}
set
{
settings[SettingsNames.limitSize] = value;
}
}
public string ParseResult
{
get
{
return settings.ContainsKey(SettingsNames.parseResult) ? settings[SettingsNames.parseResult] as string : null;
}
set
{
settings[SettingsNames.parseResult] = value;
}
}
public bool RegisterScript { get; set; }
int ParseTimeout(string v)
{
string[] units = new string[] { "ms", "ss", "mm", "hh" };
Func<string, int> fn = u =>
{
for (int i = 0; i < units.Length; i++) { if (units[i] == u)return i; }
return 0;
};
Regex rgx = new Regex(@"^\s*(\d+)\s*(ms|(ss)|(mm)|(hh))?\s*$", RegexOptions.IgnoreCase);
var m = rgx.Match(v);
if (m == null || !m.Success)
{ throw new ArgumentException("“" + v + "”无效的表达式,如二十四小时“24hh”的格式"); }
int time;
int.TryParse(m.Groups[1].Value, out time);
int index = fn(m.Groups[2].Success ? m.Groups[2].Value.ToLower() : "ss");
while (index-- > 0)
{
time *= (index == 1 ? 1000 : 60);
}
return time;
}
long ParseSize(string v)
{
string[] units = new string[] { "B", "KB", "MB", "GB", "TB" };
Func<string, int> fn = u =>
{
for (int i = 0; i < units.Length; i++) { if (units[i] == u)return i; }
return 0;
};
Regex rgx = new Regex(@"^\s*(\d+)\s*(B|(KB)|(MB)|(GB)|(TB))?\s*$", RegexOptions.IgnoreCase);
var m = rgx.Match(v);
if (m == null || !m.Success)
{ throw new ArgumentException("“"+v+"”无效的表达式请参照“232MB”的格式"); }
long size;
long.TryParse(m.Groups[1].Value, out size);
int index = fn(m.Groups[2].Success ? m.Groups[2].Value.ToUpper() : "MB");
while (index-- > 0)
{
size *= 1024;
}
return size;
}
string ParseSetting(SettingsNames key,object v)
{
if (!settings.ContainsKey(key)) return null;
string s;
long size;
switch (key)
{
case SettingsNames.url:
s= v as string;
if (!string.IsNullOrWhiteSpace(s))
{ s = "\"" + ConvertHelper.ConvertToClientString(ResolveUrl(s)) + "\""; }
return s;
case SettingsNames.maxQueue:
return v == null ? null : v.ToString();
case SettingsNames.blobSize:
size = ParseSize(v as string);
long max=(((HttpRuntimeSection)WebConfigurationManager.OpenWebConfiguration("/").GetSection("system.web/httpRuntime")).MaxRequestLength-2)*1024;
return (size > max ? max : size).ToString();
case SettingsNames.limitSize:
size = ParseSize(v as string);
return size.ToString();
case SettingsNames.timeout:
return ParseTimeout(v as string).ToString();
case SettingsNames.dragable:
case SettingsNames.multiple:
return ((bool)v) ? "true" : "false";
case SettingsNames.sliced:
return ((UploaderSliceds)v) != UploaderSliceds.Auto ? ((UploaderSliceds)v).GetHashCode().ToString() : null;
case SettingsNames.dragContainer:
case SettingsNames.placeholder:
case SettingsNames.progress:
s = (v + "").Trim();
if (s.StartsWith("$:"))
{ s = s.Substring(2); }
else { s = "\"" + ConvertHelper.ConvertToClientString(s) + "\""; }
return s;
case SettingsNames.parseResult:
s = (v + "").Trim();
if (s.StartsWith("javascript:", StringComparison.CurrentCultureIgnoreCase))
{ s = "function(serverData){\n" + s.Substring(11) + "\n}"; }
return s;
default:
s= v as string;
if (!string.IsNullOrWhiteSpace(s))
{ s = "\"" + ConvertHelper.ConvertToClientString(s) + "\""; }
return s;
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (RegisterScript) { RegisterClientScript(); }
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
Dictionary<string, object> AddedKey;
bool flag;
StringBuilder sb = new StringBuilder();
foreach (var s in settings)
{
string v = ParseSetting(s.Key, s.Value);
if (!string.IsNullOrWhiteSpace(v))
{ sb.AppendFormat("{0}{1}:{2}", sb.Length > 0 ? "," : null, s.Key, v); }
}
if (!string.IsNullOrWhiteSpace(_token))
{
if (PostParameters == null) { PostParameters = new PostParametersCollection(); }
PostParameters.Insert(0, new PostParameter("token", _token));
}
if (PostParameters != null && PostParameters.Count > 0)
{
AddedKey = new Dictionary<string, object>();
flag = false;
sb.AppendFormat("{0}params:{{", sb.Length > 0 ? "," : null);
foreach (var s in PostParameters)
{
AddedKey.Add(s.Key, null);
sb.AppendFormat("{0}\"{1}\":\"{2}\"", flag ? "," : null
, ConvertHelper.ConvertToClientString(s.Key).Trim()
, ConvertHelper.ConvertToClientString(s.Value).Trim());
flag = true;
}
sb.Append("}");
AddedKey = null;
}
if (sb.Length > 0)
{
sb.Insert(0, "{\n");
sb.Append("\n}");
}
if (ClientEvents != null && ClientEvents.Count > 0)
{
flag = false;
AddedKey = new Dictionary<string, object>();
foreach (var s in ClientEvents)
{
string k = s.EventName.ToString(), v = s.Handle;
if (string.IsNullOrWhiteSpace(v)) continue;
AddedKey.Add(k, null);
if (v.StartsWith("javascript:", StringComparison.CurrentCultureIgnoreCase))
{ v = "function(file,args){\n" + v.Substring(11) + "\n}"; }
sb.AppendFormat("{0}\"{1}\":{2}", flag ? "," : ",\n{\n", k, v);
flag = true;
}
if (flag)
{
sb.Append("\n}");
}
}
string js = "var " + this.ClientID + "=new Uploader(" + sb.ToString() + ")";
writer.Write("<script>\n"+js+"\n</script>");
}
protected override void CreateChildControls()
{
base.CreateChildControls();
if (ViewTemplate != null)
{
ViewTemplate item = new ViewTemplate();
ViewTemplate.InstantiateIn(item);
this.Controls.Add(item);
}
}
string GetWebResourceUrl(string rn)
{
return Page.ClientScript.GetWebResourceUrl(this.GetType(), rn);
}
void RegisterClientScript()
{
if (this.Page.Header != null)
{
string id = "Uploader.release.min.js";
if (this.Page.Header.FindControl(id) == null)
{
Control container = new Control();
container.ID = id;
HtmlGenericControl js = new HtmlGenericControl("script");
js.Attributes.Add("src", GetWebResourceUrl("Html5Uploader.Controls.Uploader.release.min.js"));
js.InnerHtml = " ";
container.Controls.Add(js);
Page.Header.Controls.Add(js);
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Html5Uploader.Controls
{
public class PostParametersCollection : List<PostParameter>
{
public PostParametersCollection()
: base()
{ }
public PostParameter this[string key]
{
get
{
return this.Find(p => string.Equals(key, p.Key, StringComparison.CurrentCultureIgnoreCase));
}
set
{
PostParameter par = this.Find(p => string.Equals(key, p.Key
, StringComparison.CurrentCultureIgnoreCase));
par.Key = value.Key;
par.Value = value.Value;
}
}
}
public class PostParameter
{
public PostParameter() { }
public PostParameter(string k, string v)
{ Key = k; Value = v; }
public string Key { get; set; }
public string Value { get; set; }
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
namespace Html5Uploader.Controls
{
public class ViewTemplate : Control, INamingContainer
{
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Html5Uploader
{
public class FileUploadComplete
{
public FileUploadComplete(string FilePath, long Size, string Message, Exception error = null)
{
this.FilePath = FilePath;
this.Message = Message;
this.Error = error;
this.Size = Size;
}
public FileUploadComplete(string FilePath,long Size, bool Sliced = false, long BlobIndex = 0, long BlobCount = 1, string Message = null, Exception error = null)
: this(FilePath, Size, Message, error)
{
this.Sliced = Sliced;
this.BlobCount = BlobCount;
this.BlobIndex = BlobIndex;
}
public long Size { get; private set; }
public bool Sliced { get; private set; }
public long BlobIndex { get; private set; }
public long BlobCount { get; private set; }
public string FilePath { get; private set; }
string _fileName;
public string FileName
{
get
{
if (_fileName == null && !string.IsNullOrWhiteSpace(FilePath))
{
_fileName = Path.GetFileName(FilePath);
}
return _fileName;
}
}
public Exception Error { get;private set; }
public string Message { get;set; }
public object Context { get; set; }
}
}

View File

@@ -0,0 +1,529 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Helper;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Configuration;
using System.Web.Security;
using System.Web.SessionState;
namespace Html5Uploader
{
public class InvalidDataBlobException : Exception
{
public InvalidDataBlobException() { }
public InvalidDataBlobException(string message):base(message) { }
public InvalidDataBlobException(string message, Exception innerException) : base(message, innerException) { }
public InvalidDataBlobException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
public class ValidateArguments {
public ValidateArguments(HttpPostedFile file, string fileName, string[] accepts)
{
this.File = file;
this.AcceptsTypes = accepts;
this.Validation = true;
this.FileName = fileName;
}
public HttpPostedFile File { get; private set; }
public string FileName { get; private set; }
public string[] AcceptsTypes { get; private set; }
public bool Validation { get; set; }
}
public class CompleteArguments {
public CompleteArguments(IEnumerable<FileUploadComplete> data)
{
FileUploadCompletes = data;
}
public bool Cancel { get; set; }
public IEnumerable<FileUploadComplete> FileUploadCompletes { get;private set; }
}
public class FilesUploadHandler : IHttpHandler,IDisposable,IRequiresSessionState
{
public event Action<FilesUploadHandler, Exception> Error;
public event Action<FilesUploadHandler, CompleteArguments> Complete;
public event Action<FilesUploadHandler, ValidateArguments> Validate;
#region
ResumableInfoProvider _provider;
protected virtual ResumableInfoProvider Provider {
get {
if (_provider == null)
{
_provider = new ResumableInfoXmlProvider();
}
return _provider;
}
}
bool? _sliced;
protected bool Sliced {
get {
if (!_sliced.HasValue)
{
bool t;
_sliced = bool.TryParse(Form["sliced"] ?? Request.QueryString["sliced"], out t) && t;
}
return _sliced.Value;
}
}
long? _blobIndex;
protected long BlobIndex
{
get
{
if (!_blobIndex.HasValue)
{
long t;
_blobIndex = long.TryParse(Form["blobIndex"] ?? Request.QueryString["blobIndex"], out t) ? t : 0;
}
return _blobIndex.Value;
}
}
long? _blobCount;
protected long BlobCount
{
get
{
if (!_blobCount.HasValue)
{
long t;
_blobCount = long.TryParse(Form["blobCount"] ?? Request.QueryString["blobCount"], out t) ? t : 1;
}
return _blobCount.Value;
}
}
long? _blobSize;
protected long BlobSize
{
get
{
if (!_blobSize.HasValue)
{
long t;
_blobSize = long.TryParse(Form["blobSize"] ?? Request.QueryString["blobSize"], out t) ? t : 0;
}
return _blobSize.Value;
}
}
long? _fileSize;
protected long FileSize
{
get
{
if (!_fileSize.HasValue)
{
long t;
if (Sliced)
{
_fileSize = long.TryParse(Form["fileSize"] ?? Request.QueryString["fileSize"], out t) ? t : 0;
}
else {
_fileSize = HasFiles ? Files[0].ContentLength : 0;
}
}
return _fileSize.Value;
}
}
Guid? _key;
protected Guid ResumableKey
{
get
{
if (!_key.HasValue)
{
Guid t;
_key = Guid.TryParse(Form["resumableKey"] ?? Request.QueryString["resumableKey"], out t) ? t : Guid.Empty;
}
return _key.Value;
}
}
string _fileName;
protected string FileName {
get
{
if (_fileName == null) {
_fileName = Sliced ? (Form["fileName"] ?? Request.QueryString["fileName"]) : HasFiles ? Files[0].FileName : string.Empty;
}
return _fileName;
}
}
string _fileType;
protected string FileType
{
get
{
if (_fileType == null)
{
_fileType = Sliced ? (Form["fileType"] ?? Request.QueryString["fileType"]) : (HasFiles ? Files[0].ContentType : string.Empty);
}
return _fileType;
}
}
ResumableInfo _resumableInfo;
protected virtual ResumableInfo ResumableInfo
{
get {
if (_resumableInfo == null)
{
_resumableInfo = ResumableKey == Guid.Empty ? Provider.GetResumableInfo(FileName, FileType, FileSize, BlobSize, BlobCount) : Provider.GetResumableInfo(ResumableKey);
if (_resumableInfo == null && Guid.Empty != ResumableKey)
{
throw new ArgumentException("无效的键值");
}
///如果已经上传了部分文件,且部件文件已丢失,那么重新再传。
if (_resumableInfo != null && !string.IsNullOrWhiteSpace(_resumableInfo.StorePath) && !File.Exists(Context.Server.MapPath("~" + _resumableInfo.StorePath)))
{
Provider.DeleteResumableInfo(_resumableInfo.Key);
_resumableInfo = null;
}
if (_resumableInfo == null)
{
_resumableInfo = new ResumableInfo(FileName, FileType,null, FileSize, BlobSize, BlobCount);
}
}
return _resumableInfo;
}
}
protected virtual void SaveResumableInfo(ResumableInfo info)
{
Provider.SaveResumableInfo(info);
}
protected virtual void RemoveResumableInfo(ResumableInfo info)
{
Provider.DeleteResumableInfo(info.Key);
}
#endregion
#region
string[] _types;
string[] AcceptsTypes
{
get
{
if (_types == null)
{
_types = string.IsNullOrWhiteSpace(Form["types"]) ? new string[0] : Form["types"].Trim().Split(';');
}
return _types;
}
}
string _token;
protected string Token {
get {
if (_token == null)
{
_token = Form["token"] ?? string.Empty;
}
return _token;
}
}
HttpContext _context;
protected HttpContext Context { get { return _context; } }
protected HttpRequest Request { get { return _context != null ? _context.Request : null; } }
protected NameValueCollection Form { get { return Request == null ? null : Request.Form; } }
protected HttpResponse Response { get { return _context != null ? _context.Response : null; } }
protected IPrincipal User { get { return _context == null ? null : _context.User; } }
protected HttpFileCollection Files { get { return Request != null ? Request.Files : null; } }
protected bool HasFiles { get { return Files != null && Files.Count > 0; } }
protected bool IsAuthenticated { get { return User != null && User.Identity != null && User.Identity.IsAuthenticated; } }
#endregion
#region IHttpHandler
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
try
{
_context = context;
Init();
////////验证用户的合法身份
//if (!IsAuthenticated)
//{ throw new HttpException(503, null); }
string method = Request.QueryString["method"] ?? Form["method"];
switch (method)
{
case "getResumableInfo":
Response.Clear();
Response.Write(string.Format("{{key:\"{0}\",index:{1}}}", ResumableInfo.Key, ResumableInfo.BlobIndex));
SaveResumableInfo(ResumableInfo);
return;
case "deleteResumable":
Response.Clear();
DeleteResumable();
Response.Write("true");
return;
}
var outputs=Save();
if (Sliced)
{
if (BlobIndex >= BlobCount - 1)
{
RemoveResumableInfo(ResumableInfo);
}
else
{
SaveResumableInfo(ResumableInfo);
}
}
bool completed = false;
if (Complete != null && (!Sliced||(Sliced && BlobIndex >= BlobCount - 1)))
{
CompleteArguments arg = new CompleteArguments(outputs);
Complete(this, arg);
completed = arg.Cancel;
}
if (!completed)
{
if (outputs == null)
{
Response.Write("null");
}
else
{
StringBuilder sb = new StringBuilder();
foreach (var fuc in outputs)
{
sb.Append((sb.Length > 0 ? "," : "") + GetJSON(fuc));
}
if (outputs.Count() > 1)
{
sb.Insert(0, "[");
sb.Append("]");
}
Response.Write(sb);
}
}
}
catch (Exception exp) {
if (exp is InvalidDataBlobException || exp.InnerException is InvalidDataBlobException)
{ DeleteResumable(); }
if (Error != null)
{
Error(this, exp);
}
else {
Response.Clear();
Response.Write("{\"err\":true,\"msg\":\"" + ConvertHelper.ConvertToClientString(exp.Message) + "\"}");
}
}
finally
{
Dispose();
}
}
#endregion
string _storeDirectory;
protected virtual string StoreDirectory
{
get
{
if (_storeDirectory == null)
{
string p = (WebConfigurationManager.AppSettings["Html5Uploader:FilesStoreDirectory"] ?? "").Trim().Replace('\\', '/');
if (0 == p.Length)
{
p = "/files";
}
else
{
if (p.StartsWith("~/"))
{
p = p.TrimStart('~');
}
else if (!p.StartsWith("/"))
{
p = "/" + p;
}
}
_storeDirectory = p;
}
return _storeDirectory;
}
}
public virtual void Dispose()
{
if (_provider != null)
{ _provider.Dispose(); }
}
protected virtual string CreateStorePath(string directory)
{
string AbsoluteUploadDirectory = Context.Server.MapPath("~" + directory)
, n = Path.GetFileNameWithoutExtension(FileName)
, ext = Path.GetExtension(FileName)
, p = Path.Combine(AbsoluteUploadDirectory, n + ext);
int i = 0;
while (File.Exists(p))
{
p = Path.Combine(AbsoluteUploadDirectory, n + "(" + (++i) + ")" + ext);
}
return Path.Combine(directory, Path.GetFileName(p)).Replace("\\", "/");
}
protected virtual string CreateStorePath()
{
return CreateStorePath(StoreDirectory);
}
protected virtual void Init() {}
protected virtual string GetJSON(FileUploadComplete fuc)
{
bool err = false;
if (fuc.Error != null)
{
err = true;
if (string.IsNullOrWhiteSpace(fuc.Message)) { fuc.Message = fuc.Error.Message; }
}
return string.Format("{{{0}\"msg\":\"{1}\",\"filePath\":\"{2}\",\"name\":\"{3}\"{4}}}"
, err ? "\"err\":true," : null
, err ? fuc.Message : string.IsNullOrWhiteSpace(fuc.Message) ? "文件保存成功" : ConvertHelper.ConvertToClientString(fuc.Message)
, ConvertHelper.ConvertToClientString(fuc.FilePath), ConvertHelper.ConvertToClientString(fuc.FileName)
, fuc.Sliced ? string.Format(",\"sliced\":true,\"blobIndex\":{0},\"blobCount\":{1}", fuc.BlobIndex, fuc.BlobCount) : null);
}
protected bool IsValidation(HttpPostedFile file)
{
if (Sliced)
{
if (file != null && file.InputStream.Length > ResumableInfo.BlobSize)
{
throw new InvalidDataBlobException("无效的数据包。");
}
if (!string.IsNullOrWhiteSpace(ResumableInfo.StorePath))
{
string physicalPath = Context.Server.MapPath("~" + ResumableInfo.StorePath);
if (File.Exists(physicalPath) && new FileInfo(physicalPath).Length + file.InputStream.Length > ResumableInfo.FileSize)
{
throw new InvalidDataBlobException("无效的数据包。");
}
}
}
bool validation = false;
string name = Sliced ? FileName : file.FileName;
if (AcceptsTypes == null || AcceptsTypes.Length == 0) { validation = true; }
else
{
foreach (var accept in AcceptsTypes)
{
if (string.IsNullOrWhiteSpace(accept)) continue;
if (Regex.IsMatch(name, Regex.Escape(accept.Trim()) + "$", RegexOptions.IgnoreCase))
{
validation = true;
break;
}
}
}
if (Validate != null)
{
string fileName=Sliced?FileName:Path.GetFileName(file.FileName);
ValidateArguments args = new ValidateArguments(file, fileName, AcceptsTypes);
args.Validation = validation;
Validate(this, args);
validation = args.Validation;
}
return validation;
}
protected virtual IEnumerable<FileUploadComplete> Save() {
FileUploadComplete fuc = null;
if (HasFiles)
{
if (Sliced)
{
try
{
for (int i = 0; i < Files.Count; i++)
{
HttpPostedFile f = Files[i];
fuc = SaveFile(f);
}
}
catch (Exception exp) { fuc = new FileUploadComplete(this.FileName,FileSize,true, ResumableInfo.BlobIndex, ResumableInfo.BlobCount, null, exp); }
return new FileUploadComplete[] { fuc };
}
else
{
List<FileUploadComplete> list = new List<FileUploadComplete>();
for (int i = 0; i < Files.Count; i++)
{
HttpPostedFile f = Files[i];
try
{
fuc = SaveFile(f);
}
catch (Exception exp) {
fuc = new FileUploadComplete(f.FileName,f.ContentLength,null, exp);
}
list.Add(fuc);
}
return list;
}
}
return null;
}
protected virtual FileUploadComplete SaveFile(HttpPostedFile file)
{
if (file == null || file.ContentLength <= 0)
{
throw new ArgumentException("文件为空的。");
}
if (!IsValidation(file))
{ throw new ArgumentException("无效的文件类型。"); }
string storepath = Sliced ? (string.IsNullOrWhiteSpace(ResumableInfo.StorePath) ? (ResumableInfo.StorePath = CreateStorePath()) : ResumableInfo.StorePath)
: CreateStorePath()
, physicalPath = Context.Server.MapPath("~" + storepath),dir = Path.GetDirectoryName(physicalPath);
if (!Directory.Exists(dir)){Directory.CreateDirectory(dir);}
if (Sliced)
{
using (BinaryWriter bw = new BinaryWriter(new FileStream(physicalPath, FileMode.Append, FileAccess.Write, FileShare.Read)))
{
byte[] buffer = new byte[1024];
while (0 < file.InputStream.Read(buffer, 0, buffer.Length))
{
bw.Write(buffer, 0, buffer.Length);
}
bw.Flush();
}
ResumableInfo.BlobIndex = ResumableInfo.BlobIndex + 1;
}
else
{
file.SaveAs(physicalPath);
}
return Sliced ? new FileUploadComplete(storepath, FileSize, Sliced, ResumableInfo.BlobIndex, ResumableInfo.BlobCount)
: new FileUploadComplete(storepath, file.ContentLength, null);
}
protected virtual void DeleteResumable(Guid? key = null)
{
var k = key ?? ResumableKey;
var info = Provider.GetResumableInfo(k);
if (info != null)
{
if (!string.IsNullOrWhiteSpace(info.StorePath))
{
string physicalPath = Context.Server.MapPath("~" + info.StorePath);
if (File.Exists(physicalPath)) { File.Delete(physicalPath); }
}
RemoveResumableInfo(info);
}
}
}
}

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{07F2A054-679A-4AA7-8C78-DAFEBF6D2EEF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Html5Uploader</RootNamespace>
<AssemblyName>Html5Uploader</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="HtmlAgilityPack, Version=1.3.0.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>L:\学习\编程类\C#\DLL\html解析器\HtmlAgilityPack.1.4.6\Net40\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Controls\Enums.cs" />
<Compile Include="Controls\PostParametersCollection.cs" />
<Compile Include="Controls\ClientEventsCollection.cs" />
<Compile Include="Controls\ViewTemplate.cs" />
<Compile Include="FilesUploadHandler.cs" />
<Compile Include="FileUploadComplete.cs" />
<Compile Include="ResumableInfo.cs" />
<Compile Include="ResumableInfoProvider.cs" />
<Compile Include="ResumableInfoXmlManager.cs" />
<Compile Include="SlicedSet.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Controls\Html5UploaderClient.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Controls\Uploader.release.min.js" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Helper\Helper.csproj">
<Project>{6c6c0829-dfb5-4ae1-b763-7803d23e17e9}</Project>
<Name>Helper</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,38 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Web.UI;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Html5Uploader")]
[assembly: AssemblyDescription("Jackson.bruce@live.com 技术支持")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Jackson.bruce")]
[assembly: AssemblyProduct("Html5Uploader")]
[assembly: AssemblyCopyright("© 2014 Jackson.bruce")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("90fbfcff-11fc-43a3-8f1c-0ede65ff2539")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: WebResource("Html5Uploader.Controls.Uploader.release.min.js", "application/x-javascript")]

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Html5Uploader
{
public class ResumableInfo
{
public ResumableInfo(string FileName
, string FileType
, string StorePath
, long FileSize
, long BlobSize
, long BlobCount
, Guid? Key=null
, long BlobIndex=0
, DateTime? CreateDate=null)
{
this.StorePath = StorePath;
this.Key = Key ?? Guid.NewGuid();
this.FileName = FileName;
this.FileType = FileType;
this.FileSize = FileSize;
this.BlobSize = BlobSize;
this.BlobCount = BlobCount;
this.BlobIndex = BlobIndex;
this.CreateDate = CreateDate ?? DateTime.Now;
}
public Guid Key { get;protected set; }
/// <summary>
/// 文件名称
/// </summary>
public string FileName { get; protected set; }
/// <summary>
/// 文件类型
/// </summary>
public string FileType { get; protected set; }
/// <summary>
/// 存储位置
/// </summary>
public string StorePath { get; set; }
/// <summary>
/// 文件大小
/// </summary>
public long FileSize { get; protected set; }
/// <summary>
/// 切片大小
/// </summary>
public long BlobSize { get; protected set; }
/// <summary>
/// 切片总数
/// </summary>
public long BlobCount { get; protected set; }
/// <summary>
/// 已经完成的切片索引
/// </summary>
public long BlobIndex { get; set; }
/// <summary>
/// 创建的时间
/// </summary>
public DateTime CreateDate { get; protected set; }
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Html5Uploader
{
public abstract class ResumableInfoProvider:IDisposable
{
public abstract IEnumerable<ResumableInfo> ResumableInfos { get; }
public abstract ResumableInfo GetResumableInfo(Guid key);
public abstract ResumableInfo GetResumableInfo(string fileName, string fileType, long fileSize, long blobSize, long blobCount);
public abstract void SaveResumableInfo(ResumableInfo info);
public abstract void DeleteResumableInfo(Guid key);
public abstract void Dispose();
}
}

View File

@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.Configuration;
using System.IO;
using System.Xml.Linq;
namespace Html5Uploader
{
public class ResumableInfoXmlProvider : ResumableInfoProvider
{
static object lockObject = new object();
public ResumableInfoXmlProvider() {}
protected virtual string ElementName{
get {
return "resumable";
}
}
protected virtual string GetStorePath()
{
string p = (WebConfigurationManager.AppSettings["Html5Uploader:StorePath"] ?? "").Trim().Replace('\\','/');
if (0==p.Length)
{
p = "~/config/ResumableFilesStore.xml";
}
else {
if (p.StartsWith("/"))
{
p = "~" + p;
}
else if(!p.StartsWith("~/")) {
p = Path.Combine("~/", p);
}
}
p = HttpContext.Current.Server.MapPath(p);
return p;
}
protected virtual void UpdateElement(ResumableInfo info,XElement e)
{
e.Attr("key", info.Key);
e.Attr("fileName",info.FileName);
e.Attr("fileType",info.FileType);
e.Attr("storePath",info.StorePath);
e.Attr("fileSize",info.FileSize);
e.Attr("blobSize",info.BlobSize);
e.Attr("blobCount",info.BlobCount);
e.Attr("blobIndex",info.BlobIndex);
e.Attr("createDate", info.CreateDate);
}
IEnumerable<ResumableInfo> _resumableInfos;
public override IEnumerable<ResumableInfo> ResumableInfos
{
get {
if (_resumableInfos == null)
{
string key= "Html5Uploader.ResumableInfoXmlManager.ResumableInfos";
_resumableInfos = HttpRuntime.Cache[key] as IEnumerable<ResumableInfo>;
if (_resumableInfos == null)
{
XDocument doc;
string store=GetStorePath();
lock (lockObject)
{
if (File.Exists(store))
{
doc = XDocument.Load(store);
}
else
{
doc = new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement(ElementName + "s"));
string dir = Path.GetDirectoryName(store);
if (!Directory.Exists(dir))
{ Directory.CreateDirectory(dir); }
doc.Save(store);
}
}
_resumableInfos = (from n in doc.Root.Elements(ElementName)
let item = new ResumableInfo(n.Attr("fileName")
, n.Attr("fileType")
, n.Attr("storePath")
, n.Attr<long>("fileSize")
, n.Attr<long>("blobSize")
, n.Attr<long>("blobCount")
, n.AttrStruct<Guid>("key")
, n.Attr<long>("blobIndex")
, n.Attr<DateTime>("createDate"))
where item.Key != Guid.Empty
select item).ToArray();
HttpRuntime.Cache.Insert(key, _resumableInfos
, new CacheDependency(store)
, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(1));
}
}
return _resumableInfos;
}
}
public override ResumableInfo GetResumableInfo(Guid key)
{
foreach (var e in ResumableInfos)
{
if (e.Key == key)
{
return e;
}
}
return null;
}
public override ResumableInfo GetResumableInfo(string fileName, string fileType, long fileSize, long blobSize, long blobCount)
{
foreach (var e in ResumableInfos)
{
if (string.Equals(e.FileName, fileName, StringComparison.CurrentCultureIgnoreCase)
&& e.FileSize == fileSize
&& e.BlobSize == blobSize
&& e.BlobCount == blobCount
//如果类型是空的,那么智能忽略,否则同时比较类型
&& (string.IsNullOrWhiteSpace(e.FileType) || string.IsNullOrWhiteSpace(fileType) || string.Equals(e.FileType, fileType, StringComparison.CurrentCultureIgnoreCase))
)
{
return e;
}
}
return null;
}
public override void SaveResumableInfo(ResumableInfo info)
{
XDocument doc;
XElement e =null;
//启动线程保护,防止多个线程同时写入文件
lock (lockObject)
{
string store = GetStorePath();
if (File.Exists(store))
{
doc = XDocument.Load(store);
var xe = from x in doc.Root.Elements(ElementName) select x;
foreach (var x in xe)
{
if (x.Attr<Guid>("key") == info.Key)
{
e = x;
break;
}
}
if (e == null)
{
e = new XElement(ElementName);
doc.Root.Add(e);
}
UpdateElement(info, e);
}
else
{
e = new XElement(ElementName);
UpdateElement(info, e);
doc = new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement(ElementName + "s", e));
string dir = Path.GetDirectoryName(store);
if (!Directory.Exists(dir))
{ Directory.CreateDirectory(dir); }
}
doc.Save(store);
}
}
public override void DeleteResumableInfo(Guid key)
{
string store = GetStorePath();
//启动线程保护,防止多个线程同时写入文件
lock (lockObject)
{
if (File.Exists(store))
{
XDocument doc = XDocument.Load(store);
var xe = (from x in doc.Root.Elements(ElementName) select x).ToArray();
foreach (var x in xe)
{
if (x.Attr<Guid>("key") == key)
{
x.Remove();
break;
}
}
doc.Save(store);
}
}
}
public override void Dispose()
{
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Html5Uploader
{
public enum SlicedSet
{
Auto = 0
,
Enabled=1
,
Disabled =2
}
}

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{152482F9-A932-4C5A-914F-F7D646921286}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>HTML5Uploader</RootNamespace>
<AssemblyName>HTML5UploaderWebSiteTest</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<TargetFrameworkProfile />
<UseGlobalApplicationHostFile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Html5Uploader, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>bin\Html5Uploader.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<None Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</None>
<None Include="Web.Release.config">
<DependentUpon>Web.config</DependentUpon>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="index.aspx" />
<Content Include="index.html" />
<Content Include="packages.config" />
<Content Include="Handler1.ashx" />
<None Include="Scripts\jquery-2.1.1.intellisense.js" />
<Content Include="Scripts\jquery-2.1.1.js" />
<Content Include="Scripts\jquery-2.1.1.min.js" />
<Content Include="Scripts\Uploader.js" />
<Content Include="Web.config" />
<Content Include="Scripts\jquery-2.1.1.min.map" />
<Content Include="Scripts\Uploader.Release.js" />
</ItemGroup>
<ItemGroup>
<Compile Include="Handler1.ashx.cs">
<DependentUpon>Handler1.ashx</DependentUpon>
</Compile>
<Compile Include="index.aspx.cs">
<DependentUpon>index.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="index.aspx.designer.cs">
<DependentUpon>index.aspx</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>53119</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:53119/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

1
Uploader/Handler1.ashx Normal file
View File

@@ -0,0 +1 @@
<%@ WebHandler Language="C#" CodeBehind="Handler1.ashx.cs" Class="HTML5Uploader.Handler1" %>

224
Uploader/Handler1.ashx.cs Normal file
View File

@@ -0,0 +1,224 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;
namespace HTML5Uploader
{
/// <summary>
/// Handler1 的摘要说明
/// </summary>
public class Handler1 : Html5Uploader.FilesUploadHandler
{
//object LockObject = new object();
//static List<byte[]> Data;
//public void ProcessRequest(HttpContext context)
//{
// ////bool sliced;
// ////bool.TryParse(context.Request.Form["sliced"], out sliced);
// ////var files = context.Request.Files;
// ////if (files != null && files.Count > 0)
// ////{
// //// var file = files[0];
// //// string name =sliced? Path.GetFileName(file.FileName):context.Request.Form["name"], tempFilePath = context.Server.MapPath("~/" + name);
// //// if (sliced)
// //// {
// //// byte[] buffer = new byte[file.InputStream.Length];
// //// file.InputStream.Read(buffer, 0, buffer.Length);
// //// using (BinaryWriter bw = new BinaryWriter(new FileStream(tempFilePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)))
// //// {
// //// bw.Write(buffer, 0, buffer.Length);
// //// bw.Flush();
// //// }
// //// }
// //// else {
// //// }
// ////}
// context.Response.Write("{index:100,key:'" + Guid.NewGuid() + "'}");
//}
////void v2()
////{
//// //var files = context.Request.Files;
//// //if (files != null && files.Count > 0)
//// //{
//// // long count;
//// // int index;
//// // long.TryParse(context.Request.Form["count"], out count);
//// // int.TryParse(context.Request.Form["index"], out index);
//// // lock (LockObject)
//// // {
//// // if (Data == null)
//// // {
//// // Data = new List<byte[]>(new byte[count][]);
//// // }
//// // }
//// // var file = files[0];
//// // byte[] buffer = new byte[file.InputStream.Length];
//// // file.InputStream.Read(buffer, 0, buffer.Length);
//// // lock (Data)
//// // {
//// // Data[index] = buffer;
//// // }
//// // if (index >= count - 1)
//// // {
//// // string name = context.Request.Form["name"], tempFilePath = context.Server.MapPath("~/" + name);
//// // lock (LockObject)
//// // {
//// // var arr = Data.ToArray();
//// // for (int i = 0; i < arr.Length; i++)
//// // {
//// // var d = arr[i];
//// // using (BinaryWriter bw = new BinaryWriter(new FileStream(tempFilePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)))
//// // {
//// // bw.Write(d, 0, d.Length);
//// // bw.Flush();
//// // }
//// // }
//// // Data = null;
//// // }
//// // }
//// //}
////}
////void temp(HttpContext context)
////{
//// string name = context.Request.Form["name"], tempFilePath = context.Server.MapPath("~/" + name);
//// var files = context.Request.Files;
//// long loaded, total, position;
//// long.TryParse(context.Request.Form["loaded"], out loaded);
//// long.TryParse(context.Request.Form["position"], out position);
//// if (files != null && files.Count > 0)
//// {
//// long.TryParse(context.Request.Form["total"], out total);
//// FileResumer fr = new FileResumer();
//// fr.m_FileSize = total;
//// fr.RangePos = position;
//// var file = files[0];
//// loaded += file.InputStream.Length;
//// fr.Resumer(ref file, tempFilePath);
//// //using (BinaryWriter bw = new BinaryWriter(new FileStream(tempFilePath, FileMode.Append, FileAccess.Write,FileShare.ReadWrite)))
//// //{
//// // using (BinaryReader br = new BinaryReader(files[0].InputStream))
//// // {
//// // var arr = new byte[br.BaseStream.Length];
//// // br.Read(arr, 0, arr.Length);
//// // bw.Write(arr, 0,arr.Length);
//// // //var arr = new byte[1024];
//// // //while (br.Read(arr, 0, arr.Length) > 0)
//// // //{
//// // // bw.Write(arr, 0, arr.Length);
//// // //}
//// // }
//// // bw.Flush();
//// //}
//// }
//// context.Response.Write("{loaded:" + loaded + "}");
//// //context.Response.Write(Convert.ToBase64String(Encoding.UTF8.GetBytes("kkkkkkkk")));
//// //context.Response.Write(Encoding.UTF8.GetString(Convert.FromBase64String("a2tra2tra2s=")));
////}
////async void Write(byte[] data, string tempFilePath)
////{
//// long sPosstion;
//// FileStream FStream;
//// if (File.Exists(tempFilePath))
//// {
//// FStream = File.OpenWrite(tempFilePath);
//// sPosstion = FStream.Length;
//// FStream.Seek(sPosstion, SeekOrigin.Current);//移动文件流中的当前指针
//// }
//// else
//// {
//// FStream = new FileStream(tempFilePath, FileMode.Create);
//// sPosstion = 0;
//// }
//// await FStream.WriteAsync(data, 0, data.Length);
//// FStream.Close();
//// FStream.Dispose();
////}
}
/// <summary>
/// 文件续传类
/// </summary>
public class FileResumer
{
public long m_FileSize; //文件总大小。
string m_FileMD5; //
long m_RangePos; //文件块起始位置
public long RangePos
{
set { this.m_RangePos = value; }
}
int m_RangeSize; //文件块大小
//文件读写锁,防止多个用户同时上传相同文件时,出现创建文件的错误
static ReaderWriterLock m_writeLock = new ReaderWriterLock();
public FileResumer()
{
}
/// <summary>
/// 根据文件大小创建文件。
/// 注意:多个用户同时上传相同文件时,可能会同时创建相同文件。
/// </summary>
public void CreateFile(string filePath)
{
//文件不存在则创建
if (!File.Exists(filePath))
{
//创建文件
//这里存在多个线程同时创建文件的问题。
FileStream fs = File.OpenWrite(filePath);
BinaryWriter w = new BinaryWriter(fs);
for (long i = 0; i < this.m_FileSize; ++i)
{
w.Write((byte)0);
}
w.Close();
fs.Close();
}
}
/// <summary>
/// 续传文件
/// </summary>
/// <param name="fileRange">文件块</param>
/// <param name="fileRemote">远程文件完整路径。d:\www\web\upload\201204\10\md5.exe</param>
public void Resumer(ref HttpPostedFile fileRange, string fileRemote)
{
//存在多个用户同时创建相同文件的问题。
m_writeLock.AcquireWriterLock(1000);
this.CreateFile(fileRemote);
m_writeLock.ReleaseWriterLock();
//上传的文件大小不为空
if (fileRange.InputStream.Length > 0)
{
//文件已存在,写入数据
//可能会有多个线程同时写文件。
FileStream fs = new FileStream(fileRemote, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
fs.Seek(this.m_RangePos, SeekOrigin.Begin);
byte[] ByteArray = new byte[fileRange.InputStream.Length];
fileRange.InputStream.Read(ByteArray, 0, (int)fileRange.InputStream.Length);
fs.Write(ByteArray, 0, (int)fileRange.InputStream.Length);
fs.Flush();
fs.Close();
}
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过下列特性集
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("HTML5Uploader")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HTML5Uploader")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
// 对 COM 组件不可见。如果需要
// 从 COM 访问此程序集中的某个类型,请针对该类型将 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于 typelib 的 ID
[assembly: Guid("a9dcad6a-f5ef-4bbf-97ad-35ced6e15b8c")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 内部版本号
// 修订版本
//
// 可以指定所有值,也可以使用“修订号”和“内部版本号”的默认值,
// 方法是按如下所示使用 "*":
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,550 @@

(function () {
"use strict";
//公开方法与构造函数
//实例化一个上传器参数settings说明
//object类型{...}
// placeholder:"#btnSelectFiles"//打开文件选择器的占位符可选的类型jQuery对象或者字符串类型的jQuery选择器
// multiple:true //文件选择器对话框是否支持多选,默认值true
// accept:"image/*,text/xml" //接受的文件类型,默认值是空的,即是接受全部类型
// dragable:false 可以拖拽文件上传,默认是未开启的
// dragContainer:"#container" 拖拽入的容器可选的类型jQuery对象或者字符串类型的jQuery选择器
// progress:"#box" //文件上传进度列表容器可选的类型jQuery对象或者字符串类型的jQuery选择器
// blobSize:number //文件切片上传时,单个数据块的大小,单位是字节
// sliced:number //是否支持切片上传可用值Uploader.Sliced.Auto(0),Uploader.Sliced.Enabled(1),Uploader.Sliced.Disabled(2) 默认值 Uploader.Sliced.Auto
// limitSize:number //上传文件大小限制单位是字节默认值0 表示没有限制
// url:"/fileUpload/handler" //服务端的处理程序默认值是当前浏览器的地址location.href
// params:{...} //和文件一起提交到服务端的自定义参数object类型
// parseResult //这个是个函数用来解析服务端返回的结果集 function(serverData) 返回值是object如果服务端有错误应该返回{err:true,msg:“错误描述”}的对象
var u = window.Uploader = function (settings, events) {
if (!(this instanceof u)) { return new u(settings, events) };
var s = this
, opts = settings || {}
, context = { events: {}, files: [] }
, sltfsfn = s.upload = function (files) {
for (var i = 0; i < files.length; i++) {
selecting.apply(s, [files[i], context])
}
};
s.version = u.Version;
//检查浏览器支持
s.support = u.Support;
if (!s.support) return false;
//读取设置
s.settings = function (n) {
var v = opts[n];
return typeof (v) === udfs ? defaultSettings[n] : v;
};
if (typeof (opts.params) === udfs) { opts.params = {} }
if (typeof (opts.types) == "string") { context.types = opts.types.split(';') }
//事件绑定 可用事件:
//selecting 选择文件 function(file,args) args:{ cancel: false,invalidType:false||true }
//selected 已经选择了文件 function(file)
//upload 开始上传文件 function(file,args) args:{cancel: false}
//createProgress 创建进度视图 function(file,args) args:{view:null} args.view返回已经创建的视图
//getResumableInfoHandler 获取续传信息时触发 function(url,params,callback) url服务端处理程序params文件参数 {fileType:string,fileName:string,fileSize:number,blobSize: number,blobCount:number} callback:function(ResumableInfo:{key,index}) 回调函数
//progress 更新进度视图 function(file,args) args: {view:当前视图,cancel: false,size :文件大小,loaded:已经上传的大小,percent:0 ~ 100}
//complete 文件上传完成 function(file,args) args:{view:当前视图, req: XMLHttpRequest, status:XMLHttpRequest.status}
//success 文件上传成功 function(file,args) args:{view:当前视图,responseText: XMLHttpRequest.responseText,cancel: false, req:XMLHttpRequest,responseType: XMLHttpRequest.responseType, responseXML:XMLHttpRequest.responseXML}
//error 错误处理 function(file,args) args:{ view: 当前视图,type:Uploader.ErrorType,code:number,message:string }
//drop 启动拖拽上传时dragable=true在拖拽容器上拖拽时触发的事件
//dragover 启动拖拽上传时dragable=true在拖拽容器上拖拽时触发的事件
//dragleave 启动拖拽上传时dragable=true从拖拽容器上拽出时触发的事件
s.on = function (a) {
var args = arguments;
if (args.length == 2) { setHandlers(args[0], context.events, args[1]) }
else if (a) {
for (var n in a) { setHandlers(n, context.events, a[n]) }
}
};
if (events) { s.on(events) }
var multiple = s.settings("multiple"), accept = s.settings("accept"), fs;
//
if (opts.placeholder) {
var btn = $(opts.placeholder), fileSelector;
fs = btn.find("[type='file']");
if (!fs.length) {
fs = $(fileSelector = document.createElement("input")).attr("type", "file").css({ display: 'none', opacity: 0 }).appendTo(btn)
} else { fileSelector = fs[0] }
btn.click(function () { fileSelector.click() });
if (multiple) { fs.attr("multiple", "multiple") }
if (accept) { fs.attr("accept", accept) }
fs.change(function () { sltfsfn(this.files) })
}
//else {
// fs = $("input[type='file']")//.on("change", function () { sltfsfn(this.files) });
//}
if (s.settings("dragable") || !opts.placeholder) {
var drp = s.settings("dragContainer"), defaultDragContainerFlag = false;
if (!drp) {
defaultDragContainerFlag = true;
drp = $(document.createElement("div")).attr("data-default-dragContainer", defaultDragContainerFlag).css({ display: "none", position: "fixed", "z-index": 9999999, top: 0, left: 0, bottom: 0, right: 0, opacity: 0 }).appendTo("body")
}
else if (!(drp instanceof jQuery)) { drp = $(drp) }
if (drp.length) {
var dr = drp[0]
, dragEnterfn = function (e) {
e.preventDefault();
if (defaultDragContainerFlag) { clearTimeout(dr.time); dr.time = null; drp.show() }
else { drp.addClass("over") }
}
, dragLeavefn = function (e) {
e.preventDefault();
if (defaultDragContainerFlag) {
if (!dr.time)
{ dr.time = setTimeout(function () { drp.hide() }, 10) }
}
else { drp.removeClass("over") }
};
$(document).on({
dragleave: dragLeavefn,
drop: function (e) {
e.preventDefault();
drp.removeClass("over")
},
dragenter: dragEnterfn,
dragover: dragEnterfn
});
dr.addEventListener("dragleave", function (e) {
triggerEvents("dragleave", context, function (fn) { fn.call(s, e) })
}, false);
dr.addEventListener("dragover", function (e) {
e = e || window.event;
e.stopPropagation();
dragEnterfn(e);
triggerEvents("dragover", context, function (fn) { fn.call(s, e) });
//e.dataTransfer.dropEffect = 'copy' //指定拖放视觉效果
}, false);
dr.addEventListener("drop", function (e) {
e = e || window.event;
e.stopPropagation();
dragLeavefn(e);
//获取文件列表
var files = e.dataTransfer ? e.dataTransfer.files : null;
e.cancel = false;
triggerEvents("drop", context, function (fn) { fn.call(s, e) });
if (!e.cancel && files && files.length) { sltfsfn(files) }
}, false)
}
}
}
, udfs = 'undefined';
//静态属性和方法
u.Version = { major: 1, minor: 0, revision: 0 };
u.Version.toString = function () { return this.major + "." + this.minor + "." + this.revision };
//检查浏览器支持
u.Support = typeof (window.File) !== udfs && typeof (window.FileList) !== udfs && (typeof (window.Blob) === "function" &&
(!!window.Blob.prototype.webkitSlice || !!window.Blob.prototype.mozSlice || !!window.Blob.prototype.slice || false));
u.Sliced = { Auto: 0, Enabled: 1, Disabled: 2 };
u.ErrorType = {
//无效的文件类型
InvalidType: 0
,
//超过文件上限
UpperLimit: 1
,
HttpType: 2
,
ServerType: 3
,
UserAbort: 4
,
InvalidOperation: 5
};
u.SizeToString = function (size, num) {
if (typeof (size) !== "number") return size;
var unit = "byte", units = ["KB", "MB", "GB", "TB"], l = 1024, fn = function (n) {
if (size > l) {
size = size / l;
unit = n;
return true;
}
return false;
};
for (var i = 0; i < units.length; i++)
{ if (!fn(units[i])) break }
l = Math.pow(10, (typeof (num) !== "number" || num <= 0 ? 3 : num));
return (Math.round(size * l) / l) + unit
};
//默认配置
var defaultSettings = {
url: location.href
, multiple: true
///默认是3MB
, blobSize: 1024 * 1024 * 3
, sliced: u.Sliced.Auto
, dragable: false
};
//私有方法
function isValidType(file, context) {
var s = this, n = file.name, did = false, args = { invalid: true, accept: s.settings("accept"), types: context.types };
triggerEvents("validate", context, function (fn) { fn.call(s, file, args); did = true });
if (did) { return !args.invalid }
if (!context.types) return true;
for (var i = 0; i < context.types.length; i++) {
var o = $.trim(context.types[i]);
if (!o) continue;
if (new RegExp(escape(o) + "$", "i").test(n)) {
return true
}
}
return false;
}
function setHandlers(n, e, fn) {
if (typeof (n) !== "string" || typeof (fn) !== "function") return;
var h = e[n = n.toUpperCase()];
if (!h) { h = e[n] = [] }
h.push(fn)
}
function getHandlers(n, e) {
return typeof (n) === "string" && e ? e[n.toUpperCase()] : null
}
function triggerEvents(n, c, b) {
var h = getHandlers(n, c.events);
if (h) {
for (var i = 0; i < h.length; i++) {
var fn = h[i];
if (typeof (fn) === "function") {
try { b(fn) } catch (x) { console.log(x, fn) }
}
}
}
}
//事件
function error(file, context, args, msg) {
var s = this;
s.hasError = true;
s.error = args;
triggerEvents("error", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) {
if (msg = msg || args.message) { s.view.append("<span class='err-info'>" + msg + "</span>") }
setTimeout(function () { s.view.remove() }, 5000)
}
next(context);
}
function selected(file, context) {
var s = this, prog = new Progress(s, file, context);
triggerEvents("selected", context, function (fn) { fn.call(s, file) });
if (!context.progress) { context.progress = [] }
context.progress.push(prog);
upload.call(s, file, context);
}
function selecting(file, context) {
var s = this, args = { cancel: false, invalidType: !isValidType.call(s, file, context) };
if (args.invalidType) { file.invalidType = true }
triggerEvents("selecting", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) {
context.files.push(file);
selected.apply(s, [file, context])
}
}
function upload(file, context) {
var s = this, prs = context.progress, args = { cancel: false, maxQueue: s.settings("maxQueue"), queue: context.queue, lastIndex: context.lastIndex || 0 }
, prog = context.progress[args.lastIndex];
if (typeof (args.queue) !== "number" || args.queue < 0) { args.queue = 0; }
if (args.lastIndex < 0) { args.lastIndex = 0; }
if (typeof (args.maxQueue) !== "number" || args.maxQueue < 1) { args.maxQueue = 2; }
if (args.queue >= args.maxQueue)
{ return }
context.queue = args.queue + 1;
context.lastIndex = args.lastIndex + 1;
args.progress = prog;
triggerEvents("upload", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) { prog.proceed() }
}
function createProgress(file, context) {
var s = this, ow = s.owner, args = { view: null };
triggerEvents("createProgress", context, function (fn) { fn.call(s, file, args) });
if (args.view == null) {
//创建默认视图
var p = ow.settings("progress");
if (!p) {
p = ow.settings("dragable") && (p = ow.settings("dragContainer")) && (p = p instanceof jQuery ? p : $(p)).length > 0 ? p : $("body")
}
//else if (p instanceof jQuery) { p = $(p); }
var v = args.view = $(document.createElement("div")).appendTo(p);
v.append("<h2>" + file.name + "</h2><p>size:" + u.SizeToString(file.size) + "</p><progress></progress>")
}
return s.view = args.view
}
function progress(file, context, st) {
var s = this, p, args = { cancel: false, size: s.size, sizeString: u.SizeToString(s.size), view: s.view };
if (s.sliced === true) {
args.loaded = s.loaded + Math.min(st.currentBlobLoaded, s.blobSize)
}
else {
args.loaded = Math.min(st.currentBlobLoaded, s.size)
}
p = (args.loaded / args.size) * 100;
args.percent = p;
args.loadedString = u.SizeToString(args.loaded);
triggerEvents("progress", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) {
s.bar.attr("value", args.percent)
}
}
function success(file, context, result) {
var s = this
, args = {
view: s.view, cancel: false, result: result
, req: s.xhr, responseText: s.xhr.responseText, responseType: s.xhr.responseType, responseXML: s.xhr.responseXML
};
triggerEvents("success", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) { setTimeout(function () { s.view.remove(); }, 5000) }
}
function complete(file, context) {
var s = this, args = { view: s.view, req: s.xhr, status: s.xhr.status };
context.queue--;
triggerEvents("complete", context, function (fn) { fn.call(s, file, args) });
next(context);
}
function next(context) {
var i = context.lastIndex, s;
if (i < context.progress.length) {
s = context.progress[i];
upload.call(s.owner, s.file, context);
}
}
function Progress(owner, file, context) {
this.owner = owner;
var s = this, xhr, paused, index = 0, count = 1
, size = s.size = file.size
, blobSize = s.blobSize = owner.settings("blobSize")
, sliced = s.sliced = ((sliced = owner.settings("sliced")) === u.Sliced.Enabled || (sliced === u.Sliced.Auto && size > blobSize) ? true : false)
, view = (s.view = createProgress.call(s, file, context) || $())
, bar = (s.bar = view.find("progress").attr({ "max": 100, "value": 0 }))
, limitSize = owner.settings("limitSize")
, url = owner.settings("url")
, parseResult = owner.settings("parseResult")
, appendParams = function (d) {
var ps = owner.settings("params");
if (sliced) {
d.append("blobIndex", index);
d.append("blobCount", count);
d.append("resumableKey", s.resumableKey);
d.append("sliced", sliced);
d.append("fileName", file.name);
}
d.append("types", owner.settings("types") || "");
if (owner.settings("accept")) { d.append("accept", owner.settings("accept")) }
for (var p in ps) { d.append(p, ps[p]) }
}
, send = function (f) {
xhr.open("post", url, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
var d = new FormData();
d.append("file", f);
appendParams(d);
//console.log("start:"+new Date().toLocaleTimeString());
xhr.send(d)
}
, sendBlob = function (i) {
var start = i * blobSize, end = start + blobSize;
index = i;
s.loaded = start;
if (file.slice) {
s.blob = file.slice(start, end);
}
else if (file.webkitSlice) {
s.blob = file.webkitSlice(start, end);
} else if (file.mozSlice) {
s.blob = file.mozSlice(start, end);
}
send(s.blob);
};
if (typeof (parseResult) !== "function") { parseResult = function (d) { var r; try { eval("r=" + d) } catch (e) { r = { err: true, msg: "脚本解析错误。" } } return r } }
s.file = file;
s.loaded = 0;
s.blobSize = blobSize = (sliced ? blobSize : size);
s.pause = function () {
if (!s.hasError && paused !== true) {
s.paused = paused = true;
if (xhr && file.uploading === true) {
xhr.abort();
delete file.uploading;
}
triggerEvents("pause", context, function (fn) { fn.call(s, file, { view: view }); });
context.queue--;
next(context);
}
};
s.proceed = function () {
if (s.hasError || file.uploading === true) { return; }
if (file.uploaded === true || file.canceling === true) {
error.call(s, file, context
, {
type: u.ErrorType.InvalidOperation
, message: file.canceling ? "the file is canceling" : file.uploaded ? "the file was uploaded" : "invalid operation", view: view
});
return
}
if (paused === true) {
var a = { view: view, cancel: false };
triggerEvents("proceed", context, function (fn) { fn.call(s, file, a); });
if (a.cancel) { return; }
}
file.cancel = s.paused = paused = false; file.uploading = true;
if (!sliced) { send(file); return };
var gotit = false
, args = { sliced: true, fileType: file.type, fileName: file.name, fileSize: size, blobSize: blobSize, blobCount: count }
, b = function (info) {
if (info && info.key)
{ s.resumableKey = info.key }
else { throw new Error(info.msg || info.message || "failed to initialize"); }
setTimeout(function () { sendBlob(!isNaN(info.index) ? info.index : 0) }, 0)
}
, errfn = function (a, x, p) {
if (!a) { a = { type: u.ErrorType.ServerType, message: "failed to initialize" } }
a.view = view;
error.call(s, file, context, a); if (x && x.message) console.log(x.message, p)
};
triggerEvents("getResumableInfoHandler", context, function (fn) { try { fn.call(s, url, args, b) } catch (x) { errfn(null, x, fn) } gotit = true });
if (!gotit) {
args.method = "getResumableInfo";
$.ajax({
url: url, type: "POST"
, data: args
, success: function (d) {
var resumable = null;
try {
eval("resumable=" + d);
b(resumable)
} catch (x) {
//获取初始化信息失败
errfn(null, x, d);
return
}
}
, error: function (req, txt, dd) {
//获取初始化信息失败
errfn({ type: u.ErrorType.HttpType, code: req.status, message: txt || errorThrown })
}
})
}
};
s.cancel = function () {
if (!s.hasError && file.uploaded !== true && file.cancel !== true && file.canceling !== true) {
var doit = function (o) {
if (o && !(o.err || o.error)) {
file.cancel = true; delete file.canceling; bar.attr("value", 0);
triggerEvents("cancel", context, function (fn) { fn.call(s, file, { view: view }) })
}
};
s.pause();
file.canceling = true;
if (sliced) {
$.ajax({
url: url, type: "POST", data: { method: "deleteResumable", resumableKey: s.resumableKey }
, success: function (d) {
var r = null;
try {
eval("r=" + d);
doit(r);
} catch (x) {
errfn(null, x, d);
return
}
}
})
}
else { doit(true); }
}
//
};
if (file.invalidType || (limitSize && !isNaN(limitSize) && file.size > limitSize)) {
error.call(s, file, context
, { type: file.invalidType ? u.ErrorType.InvalidType : u.ErrorType.UpperLimit, view: view, message: file.invalidType ? "无效文件类型" : "超过上传限制的大小" }
);
return
}
xhr = s.xhr = new XMLHttpRequest();
if (typeof (owner.settings("timeout")) === "number") { xhr.timeout = owner.settings("timeout") }
//事件绑定
xhr.addEventListener("readystatechange", function (e) {
//完成
if (xhr.readyState === 4) {
if (s.blob) delete s.blob;
var status = xhr.status, isSuccess = status >= 200 && status < 300 || status === 304;
if (!isSuccess) {
if (paused !== true) { error.call(s, file, context, { type: u.ErrorType.HttpType, code: status, view: view, message: xhr.statusText }) }
}
if (sliced && index >= count - 1 || !sliced) {
if (paused === false) {
complete.call(s, file, context);
s.paused = paused = true;
delete file.uploading
}
}
}
}, false);
xhr.upload.addEventListener("progress", function (e) {
progress.call(s, file, context, { currentBlobLoaded: e.loaded, currentBlobSize: e.total, index: index })
}, false);
xhr.addEventListener("load", function (e) {
var r;
if (s.hasError) return;
if (!(r = parseResult(e.target.responseText)) || (r.err || r.error) === true) {
error.call(s, file, context, { type: u.ErrorType.ServerType, view: view, message: r ? (r.msg || r.message) : "unknown" });
return
}
if (sliced && index < count - 1) {
if (paused === true) { delete file.uploading; }
else { setTimeout(function () { sendBlob(index + 1) }, 0) }
}
///完全上传成功
else {
success.call(s, file, context, r); file.uploaded = true
}
}, false);
xhr.upload.addEventListener("error", function (e) {
if (paused !== true) {
var status = xhr.readyState === 4 || xhr.readyState === 3 ? xhr.status : 0;
error.call(s, file, context, { type: u.ErrorType.HttpType, code: status, view: view, message: status === 0 ? "unknown" : xhr.statusText })
}
}, false);
if (sliced === true) {
s.count = count = Math.ceil(size / blobSize);
};
//s.proceed()
}
///扩展jQuery方法为其所有实例添加asyncUploadFiles方法
if (u.Support) {
jQuery.prototype.asyncUploadFiles = (function (b) {
return function (a, e) {
if (typeof (b) === "function") { b.apply(this, arguments) }
if (a) {
if (a.placeholder) delete a.placeholder;
if (a.dragable) delete a.dragable;
if (a.multiple) delete a.multiple
}
var up = this.uploader = new u(a, e);
jQuery.each(this, function (i, n) {
var fs = n.files;
if (fs && fs.length) { up.upload(fs) }
});
}
})(jQuery.prototype.asyncUploadFiles)
}
})();

View File

@@ -0,0 +1,586 @@

(function () {
"use strict";
//公开方法与构造函数
//实例化一个上传器参数settings说明
//object类型{...}
// placeholder:"#btnSelectFiles"//打开文件选择器的占位符可选的类型jQuery对象或者字符串类型的jQuery选择器
// multiple:true //文件选择器对话框是否支持多选,默认值true
// accept:"image/*,text/xml" //接受的文件类型,默认值是空的,即是接受全部类型
// dragable:false 可以拖拽文件上传,默认是未开启的
// dragContainer:"#container" 拖拽入的容器可选的类型jQuery对象或者字符串类型的jQuery选择器
// progress:"#box" //文件上传进度列表容器可选的类型jQuery对象或者字符串类型的jQuery选择器
// blobSize:number //文件切片上传时,单个数据块的大小,单位是字节
// sliced:number //是否支持切片上传可用值Uploader.Sliced.Auto(0),Uploader.Sliced.Enabled(1),Uploader.Sliced.Disabled(2) 默认值 Uploader.Sliced.Auto
// limitSize:number //上传文件大小限制单位是字节默认值0 表示没有限制
// url:"/fileUpload/handler" //服务端的处理程序默认值是当前浏览器的地址location.href
// params:{...} //和文件一起提交到服务端的自定义参数object类型
// parseResult //这个是个函数用来解析服务端返回的结果集 function(serverData) 返回值是object如果服务端有错误应该返回{err:true,msg:“错误描述”}的对象
var u = window.Uploader = function (settings, events) {
///将帮助信息输出到控制台,如果不要这些帮助信息,可以用 if (!(this instanceof u)){return new u(settings,events)}; 代替下面的if语句
if (!(this instanceof u)) {
console.log("实例化一个上传器参数settings说明"
+ "\n 类型是 object{...}"
+ "\n placeholder:\"#btnSelectFiles\"//打开文件选择器的占位符可选的类型jQuery对象或者字符串类型的jQuery选择器"
+ "\n multiple:true //文件选择器对话框是否支持多选,默认值true"
+ "\n accept:\"image/*,text/xml\" //接受的文件类型,默认值是空的,即是接受全部类型"
+ "\n dragable:false 可以拖拽文件上传,默认是未开启的"
+ "\n dragContainer:\"#container\" 拖拽入的容器可选的类型jQuery对象或者字符串类型的jQuery选择器"
+ "\n progress:\"#progressBox\" //文件上传进度列表容器可选的类型jQuery对象或者字符串类型的jQuery选择器"
+ "\n blobSize:number //文件切片上传时,单个数据块的大小,单位是字节"
+ "\n sliced:number //是否支持切片上传可用值Uploader.Sliced.Auto(0),Uploader.Sliced.Enabled(1),Uploader.Sliced.Disabled(2) 默认值 Uploader.Sliced.Auto"
+ "\n limitSize:number //上传文件大小限制单位是字节默认值0 表示没有限制"
+ "\n url:\"/fileUpload/handler\" //服务端的处理程序默认值是当前浏览器的地址location.href"
+ "\n params:{...} //和文件一起提交到服务端的自定义参数object类型 "
+ "\n parseResult: function(serverData) //这个是个函数用来解析服务端返回的结果集,返回值是object如果服务端有错误应该返回{err:true,msg:\"错误描述\"}的对象");
alert("文件上传器实例化的参数说明已经输出到控制台");
return;
}
var s = this
, opts = settings || {}
, context = { events: {}, files: [] }
, sltfsfn = s.upload = function (files) {
for (var i = 0; i < files.length; i++) {
selecting.apply(s, [files[i], context])
}
};
s.version = u.Version;
//检查浏览器支持
s.support = u.Support;
if (!s.support) return false;
//读取设置
s.settings = function (n) {
var v = opts[n];
return typeof (v) === udfs ? defaultSettings[n] : v;
};
if (typeof (opts.params) === udfs) { opts.params = {} }
if (typeof (opts.types) == "string") { context.types = opts.types.split(';') }
//事件绑定 可用事件:
//selecting 选择文件 function(file,args) args:{ cancel: false,invalidType:false||true }
//selected 已经选择了文件 function(file)
//upload 开始上传文件 function(file,args) args:{cancel: false}
//createProgress 创建进度视图 function(file,args) args:{view:null} args.view返回已经创建的视图
//getResumableInfoHandler 获取续传信息时触发 function(url,params,callback) url服务端处理程序params文件参数 {fileType:string,fileName:string,fileSize:number,blobSize: number,blobCount:number} callback:function(ResumableInfo:{key,index}) 回调函数
//progress 更新进度视图 function(file,args) args: {view:当前视图,cancel: false,size :文件大小,loaded:已经上传的大小,percent:0 ~ 100}
//complete 文件上传完成 function(file,args) args:{view:当前视图, req: XMLHttpRequest, status:XMLHttpRequest.status}
//success 文件上传成功 function(file,args) args:{view:当前视图,responseText: XMLHttpRequest.responseText,cancel: false, req:XMLHttpRequest,responseType: XMLHttpRequest.responseType, responseXML:XMLHttpRequest.responseXML}
//error 错误处理 function(file,args) args:{ view: 当前视图,type:Uploader.ErrorType,code:number,message:string }
//drop 启动拖拽上传时dragable=true在拖拽容器上拖拽时触发的事件
//dragover 启动拖拽上传时dragable=true在拖拽容器上拖拽时触发的事件
//dragleave 启动拖拽上传时dragable=true从拖拽容器上拽出时触发的事件
s.on = function (a) {
var args = arguments;
if (args.length == 2) { setHandlers(args[0], context.events, args[1]) }
else if (a) {
for (var n in a) { setHandlers(n, context.events, a[n]) }
}
//这个if语快是可以移除的它将事件绑定的说明输出到控制台
if (args.length === 0) {
console.log("\n selecting 选择文件 function(file,args) args:{ cancel: false,invalidType:false||true }"
+ "\n selected 已经选择了文件 function(file)"
+ "\n validate 验证文件类型时触发 function(file,args) args:{invalid:true||false,accept:\"image/*,text/xml\"} "
+ "\n upload 开始上传文件 function(file,args) args:{cancel: false}"
+ "\n createProgress 创建进度视图 function(file,args) args:{view:null} args.view返回已经创建的视图"
+ "\n getResumableInfoHandler 获取续传信息时触发 function(url,params,callback) url服务端处理程序params文件参数 {fileType:string,fileName:string,fileSize:number,blobSize: number,blobCount:number} callback:function(ResumableInfo:{key,index}) 回调函数"
+ "\n progress 更新进度视图 function(file,args) args: {view:当前视图,cancel: false,size :文件大小,loaded:已经上传的大小,percent:0 ~ 100}"
+ "\n complete 文件上传完成 function(file,args) args:{view:当前视图, req: XMLHttpRequest, status:XMLHttpRequest.status}"
+ "\n success 文件上传成功 function(file,args) args:{view:当前视图,responseText: XMLHttpRequest.responseText,cancel: false, req:XMLHttpRequest,responseType: XMLHttpRequest.responseType, responseXML:XMLHttpRequest.responseXML}"
+ "\n error 错误处理 function(file,args) args:{ view: 当前视图,type:Uploader.ErrorType,code:number,message:string }"
+ "\n drop 启动拖拽上传时dragable=true在拖拽容器上拖拽时触发的事件"
+ "\n dragover 启动拖拽上传时dragable=true在拖拽容器上拖拽时触发的事件"
+ "\n dragleave 启动拖拽上传时dragable=true从拖拽容器上拽出时触发的事件");
alert("事件绑定的说明已经输出到控制台。");
}
};
if (events) { s.on(events) }
var multiple = s.settings("multiple"), accept = s.settings("accept"), fs;
//
if (opts.placeholder) {
var btn = $(opts.placeholder), fileSelector;
fs = btn.find("[type='file']");
if (!fs.length) {
fs = $(fileSelector = document.createElement("input")).attr("type", "file").css({ display: 'none', opacity: 0 }).appendTo(btn)
} else { fileSelector = fs[0] }
btn.click(function () { fileSelector.click() });
if (multiple) { fs.attr("multiple", "multiple") }
if (accept) { fs.attr("accept", accept) }
fs.change(function () { sltfsfn(this.files) })
}
//else {
// fs = $("input[type='file']")//.on("change", function () { sltfsfn(this.files) });
//}
if (s.settings("dragable") || !opts.placeholder) {
var drp = s.settings("dragContainer"), defaultDragContainerFlag = false;
if (!drp) {
defaultDragContainerFlag = true;
drp = $(document.createElement("div")).attr("data-default-dragContainer", defaultDragContainerFlag).css({ display: "none", position: "fixed", "z-index": 9999999, top: 0, left: 0, bottom: 0, right: 0, opacity: 0 }).appendTo("body")
}
else if (!(drp instanceof jQuery)) { drp = $(drp) }
if (drp.length) {
var dr = drp[0]
, dragEnterfn = function (e) {
e.preventDefault();
if (defaultDragContainerFlag) { clearTimeout(dr.time); dr.time = null; drp.show() }
else { drp.addClass("over") }
}
, dragLeavefn = function (e) {
e.preventDefault();
if (defaultDragContainerFlag) {
if (!dr.time)
{ dr.time = setTimeout(function () { drp.hide() }, 10) }
}
else { drp.removeClass("over") }
};
$(document).on({
dragleave: dragLeavefn,
drop: function (e) {
e.preventDefault();
drp.removeClass("over")
},
dragenter: dragEnterfn,
dragover: dragEnterfn
});
dr.addEventListener("dragleave", function (e) {
triggerEvents("dragleave", context, function (fn) { fn.call(s, e) })
}, false);
dr.addEventListener("dragover", function (e) {
e = e || window.event;
e.stopPropagation();
dragEnterfn(e);
triggerEvents("dragover", context, function (fn) { fn.call(s, e) });
//e.dataTransfer.dropEffect = 'copy' //指定拖放视觉效果
}, false);
dr.addEventListener("drop", function (e) {
e = e || window.event;
e.stopPropagation();
dragLeavefn(e);
//获取文件列表
var files = e.dataTransfer ? e.dataTransfer.files : null;
e.cancel = false;
triggerEvents("drop", context, function (fn) { fn.call(s, e) });
if (!e.cancel && files && files.length) { sltfsfn(files) }
}, false)
}
}
}
, udfs = 'undefined';
//静态属性和方法
u.Version = { major: 1, minor: 0, revision: 0 };
u.Version.toString = function () { return this.major + "." + this.minor + "." + this.revision };
//检查浏览器支持
u.Support = typeof (window.File) !== udfs && typeof (window.FileList) !== udfs && (typeof (window.Blob) === "function" &&
(!!window.Blob.prototype.webkitSlice || !!window.Blob.prototype.mozSlice || !!window.Blob.prototype.slice || false));
u.Sliced = { Auto: 0, Enabled: 1, Disabled: 2 };
u.ErrorType = {
//无效的文件类型
InvalidType: 0
,
//超过文件上限
UpperLimit: 1
,
HttpType: 2
,
ServerType: 3
,
UserAbort: 4
,
InvalidOperation: 5
};
u.SizeToString = function (size, num) {
if (typeof (size) !== "number") return size;
var unit = "byte", units = ["KB", "MB", "GB", "TB"], l = 1024, fn = function (n) {
if (size > l) {
size = size / l;
unit = n;
return true;
}
return false;
};
for (var i = 0; i < units.length; i++)
{ if (!fn(units[i])) break }
l = Math.pow(10, (typeof (num) !== "number" || num <= 0 ? 3 : num));
return (Math.round(size * l) / l) + unit
};
//默认配置
var defaultSettings = {
url: location.href
, multiple: true
///默认是3MB
, blobSize: 1024 * 1024 * 3
, sliced: u.Sliced.Auto
, dragable: false
};
//私有方法
function isValidType(file, context) {
var s = this, n = file.name, did = false, args = { invalid: true, accept: s.settings("accept"), types: context.types };
triggerEvents("validate", context, function (fn) { fn.call(s, file, args); did = true });
if (did) { return !args.invalid }
if (!context.types) return true;
for (var i = 0; i < context.types.length; i++) {
var o = $.trim(context.types[i]);
if (!o) continue;
if (new RegExp(escape(o) + "$", "i").test(n)) {
return true
}
}
return false;
}
function setHandlers(n, e, fn) {
if (typeof (n) !== "string" || typeof (fn) !== "function") return;
var h = e[n = n.toUpperCase()];
if (!h) { h = e[n] = [] }
h.push(fn)
}
function getHandlers(n, e) {
return typeof (n) === "string" && e ? e[n.toUpperCase()] : null
}
function triggerEvents(n, c, b) {
var h = getHandlers(n, c.events);
if (h) {
for (var i = 0; i < h.length; i++) {
var fn = h[i];
if (typeof (fn) === "function") {
try { b(fn) } catch (x) { console.log(x, fn) }
}
}
}
}
//事件
function error(file, context, args, msg) {
var s = this;
s.hasError = true;
s.error = args;
triggerEvents("error", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) {
if (msg = msg || args.message) { s.view.append("<span class='err-info'>" + msg + "</span>") }
setTimeout(function () { s.view.remove() }, 5000)
}
next(context);
}
function selected(file, context) {
var s = this, prog = new Progress(s, file, context);
triggerEvents("selected", context, function (fn) { fn.call(s, file) });
if (!context.progress) { context.progress = [] }
context.progress.push(prog);
upload.call(s, file, context);
}
function selecting(file, context) {
var s = this, args = { cancel: false, invalidType: !isValidType.call(s, file, context) };
if (args.invalidType) { file.invalidType = true }
triggerEvents("selecting", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) {
context.files.push(file);
selected.apply(s, [file, context])
}
}
function upload(file, context) {
var s = this, prs = context.progress, args = { cancel: false, maxQueue: s.settings("maxQueue"), queue: context.queue, lastIndex: context.lastIndex || 0 }
, prog = context.progress[args.lastIndex];
if (typeof (args.queue) !== "number" || args.queue < 0) { args.queue = 0; }
if (args.lastIndex < 0) { args.lastIndex = 0; }
if (typeof (args.maxQueue) !== "number" || args.maxQueue < 1) { args.maxQueue = 2; }
if (args.queue >= args.maxQueue)
{ return }
context.queue = args.queue + 1;
context.lastIndex = args.lastIndex + 1;
args.progress = prog;
triggerEvents("upload", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) { prog.proceed() }
}
function createProgress(file, context) {
var s = this, ow = s.owner, args = { view: null };
triggerEvents("createProgress", context, function (fn) { fn.call(s, file, args) });
if (args.view == null) {
//创建默认视图
var p = ow.settings("progress");
if (!p) {
p = ow.settings("dragable") && (p = ow.settings("dragContainer")) && (p = p instanceof jQuery ? p : $(p)).length > 0 ? p : $("body")
}
//else if (p instanceof jQuery) { p = $(p); }
var v = args.view = $(document.createElement("div")).appendTo(p);
v.append("<h2>" + file.name + "</h2><p>size:" + u.SizeToString(file.size) + "</p><progress></progress>")
}
return s.view = args.view
}
function progress(file, context, st) {
var s = this, p, args = { cancel: false, size: s.size, sizeString: u.SizeToString(s.size), view: s.view };
if (s.sliced === true) {
args.loaded = s.loaded + Math.min(st.currentBlobLoaded, s.blobSize)
}
else {
args.loaded = Math.min(st.currentBlobLoaded, s.size)
}
p = (args.loaded / args.size) * 100;
args.percent = p;
args.loadedString = u.SizeToString(args.loaded);
triggerEvents("progress", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) {
s.bar.attr("value", args.percent)
}
}
function success(file, context, result) {
var s = this
, args = {
view: s.view, cancel: false, result: result
, req: s.xhr, responseText: s.xhr.responseText, responseType: s.xhr.responseType, responseXML: s.xhr.responseXML
};
triggerEvents("success", context, function (fn) { fn.call(s, file, args) });
if (!args.cancel) { setTimeout(function () { s.view.remove(); }, 5000) }
}
function complete(file, context) {
var s = this, args = { view: s.view, req: s.xhr, status: s.xhr.status };
context.queue--;
triggerEvents("complete", context, function (fn) { fn.call(s, file, args) });
next(context);
}
function next(context) {
var i = context.lastIndex, s;
if (i < context.progress.length) {
s = context.progress[i];
upload.call(s.owner, s.file, context);
}
}
function Progress(owner, file, context) {
this.owner = owner;
var s = this, xhr, paused, index = 0, count = 1
, size = s.size = file.size
, blobSize = s.blobSize = owner.settings("blobSize")
, sliced = s.sliced = ((sliced = owner.settings("sliced")) === u.Sliced.Enabled || (sliced === u.Sliced.Auto && size > blobSize) ? true : false)
, view = (s.view = createProgress.call(s, file, context) || $())
, bar = (s.bar = view.find("progress").attr({ "max": 100, "value": 0 }))
, limitSize = owner.settings("limitSize")
, url = owner.settings("url")
, parseResult = owner.settings("parseResult")
, appendParams = function (d) {
var ps = owner.settings("params");
if (sliced) {
d.append("blobIndex", index);
d.append("blobCount", count);
d.append("resumableKey", s.resumableKey);
d.append("sliced", sliced);
d.append("fileName", file.name);
}
d.append("types", owner.settings("types") || "");
if (owner.settings("accept")) { d.append("accept", owner.settings("accept")) }
for (var p in ps) { d.append(p, ps[p]) }
}
, send = function (f) {
xhr.open("post", url, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
var d = new FormData();
d.append("file", f);
appendParams(d);
//console.log("start:"+new Date().toLocaleTimeString());
xhr.send(d)
}
, sendBlob = function (i) {
var start = i * blobSize, end = start + blobSize;
index = i;
s.loaded = start;
if (file.slice) {
s.blob = file.slice(start, end);
}
else if (file.webkitSlice) {
s.blob = file.webkitSlice(start, end);
} else if (file.mozSlice) {
s.blob = file.mozSlice(start, end);
}
send(s.blob);
};
if (typeof (parseResult) !== "function") { parseResult = function (d) { var r; try { eval("r=" + d) } catch (e) { r = { err: true, msg: "脚本解析错误。" } } return r } }
s.file = file;
s.loaded = 0;
s.blobSize = blobSize = (sliced ? blobSize : size);
s.pause = function () {
if (!s.hasError && paused !== true) {
s.paused = paused = true;
if (xhr && file.uploading === true) {
xhr.abort();
delete file.uploading;
}
triggerEvents("pause", context, function (fn) { fn.call(s, file, { view: view }); });
context.queue--;
next(context);
}
};
s.proceed = function () {
if (s.hasError || file.uploading === true) { return; }
if (file.uploaded === true || file.canceling === true) {
error.call(s, file, context
, {
type: u.ErrorType.InvalidOperation
, message: file.canceling ? "the file is canceling" : file.uploaded ? "the file was uploaded" : "invalid operation", view: view
});
return
}
if (paused === true) {
var a = { view: view, cancel: false };
triggerEvents("proceed", context, function (fn) { fn.call(s, file, a); });
if (a.cancel) { return; }
}
file.cancel = s.paused = paused = false; file.uploading = true;
if (!sliced) { send(file); return };
var gotit = false
, args = { sliced: true, fileType: file.type, fileName: file.name, fileSize: size, blobSize: blobSize, blobCount: count }
, b = function (info) {
if (info && info.key)
{ s.resumableKey = info.key }
else { throw new Error(info.msg || info.message || "failed to initialize"); }
setTimeout(function () { sendBlob(!isNaN(info.index) ? info.index : 0) }, 0)
}
, errfn = function (a, x, p) {
if (!a) { a = { type: u.ErrorType.ServerType, message: "failed to initialize" } }
a.view = view;
error.call(s, file, context, a); if (x && x.message) console.log(x.message, p)
};
triggerEvents("getResumableInfoHandler", context, function (fn) { try { fn.call(s, url, args, b) } catch (x) { errfn(null, x, fn) } gotit = true });
if (!gotit) {
args.method = "getResumableInfo";
$.ajax({
url: url, type: "POST"
, data: args
, success: function (d) {
var resumable = null;
try {
eval("resumable=" + d);
b(resumable)
} catch (x) {
//获取初始化信息失败
errfn(null, x, d);
return
}
}
, error: function (req, txt, dd) {
//获取初始化信息失败
errfn({ type: u.ErrorType.HttpType, code: req.status, message: txt || errorThrown })
}
})
}
};
s.cancel = function () {
if (!s.hasError && file.uploaded !== true && file.cancel !== true && file.canceling !== true) {
var doit = function (o) {
if (o && !(o.err || o.error)) {
file.cancel = true; delete file.canceling; bar.attr("value", 0);
triggerEvents("cancel", context, function (fn) { fn.call(s, file, { view: view }) })
}
};
s.pause();
file.canceling = true;
if (sliced) {
$.ajax({
url: url, type: "POST", data: { method: "deleteResumable", resumableKey: s.resumableKey }
, success: function (d) {
var r = null;
try {
eval("r=" + d);
doit(r);
} catch (x) {
errfn(null, x, d);
return
}
}
})
}
else { doit(true); }
}
//
};
if (file.invalidType || (limitSize && !isNaN(limitSize) && file.size > limitSize)) {
error.call(s, file, context
, { type: file.invalidType ? u.ErrorType.InvalidType : u.ErrorType.UpperLimit, view: view, message: file.invalidType ? "无效文件类型" : "超过上传限制的大小" }
);
return
}
xhr = s.xhr = new XMLHttpRequest();
if (typeof (owner.settings("timeout")) === "number") { xhr.timeout = owner.settings("timeout") }
//事件绑定
xhr.addEventListener("readystatechange", function (e) {
//完成
if (xhr.readyState === 4) {
if (s.blob) delete s.blob;
var status = xhr.status, isSuccess = status >= 200 && status < 300 || status === 304;
if (!isSuccess) {
if (paused !== true) { error.call(s, file, context, { type: u.ErrorType.HttpType, code: status, view: view, message: xhr.statusText }) }
}
if (sliced && index >= count - 1 || !sliced) {
if (paused === false) {
complete.call(s, file, context);
s.paused = paused = true;
delete file.uploading
}
}
}
}, false);
xhr.upload.addEventListener("progress", function (e) {
progress.call(s, file, context, { currentBlobLoaded: e.loaded, currentBlobSize: e.total, index: index })
}, false);
xhr.addEventListener("load", function (e) {
var r;
if (s.hasError) return;
if (!(r = parseResult(e.target.responseText)) || (r.err || r.error) === true) {
error.call(s, file, context, { type: u.ErrorType.ServerType, view: view, message: r ? (r.msg || r.message) : "unknown" });
return
}
if (sliced && index < count - 1) {
if (paused === true) { delete file.uploading; }
else { setTimeout(function () { sendBlob(index + 1) }, 0) }
}
///完全上传成功
else {
success.call(s, file, context, r); file.uploaded = true
}
}, false);
xhr.upload.addEventListener("error", function (e) {
if (paused !== true) {
var status = xhr.readyState === 4 || xhr.readyState === 3 ? xhr.status : 0;
error.call(s, file, context, { type: u.ErrorType.HttpType, code: status, view: view, message: status === 0 ? "unknown" : xhr.statusText })
}
}, false);
if (sliced === true) {
s.count = count = Math.ceil(size / blobSize);
};
//s.proceed()
}
///扩展jQuery方法为其所有实例添加asyncUploadFiles方法
if (u.Support) {
jQuery.prototype.asyncUploadFiles = (function (b) {
return function (a, e) {
if (typeof (b) === "function") { b.apply(this, arguments) }
if (a) {
if (a.placeholder) delete a.placeholder;
if (a.dragable) delete a.dragable;
if (a.multiple) delete a.multiple
}
var up = this.uploader = new u(a, e);
jQuery.each(this, function (i, n) {
var fs = n.files;
if (fs && fs.length) { up.upload(fs) }
});
}
})(jQuery.prototype.asyncUploadFiles)
}
})();

File diff suppressed because it is too large Load Diff

9190
Uploader/Scripts/jquery-2.1.1.js vendored Normal file

File diff suppressed because it is too large Load Diff

4
Uploader/Scripts/jquery-2.1.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

31
Uploader/Web.Debug.config Normal file
View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 有关使用 web.config 转换的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
在下例中“SetAttributes”转换将更改
“connectionString”的值以仅在“Match”定位器
找到值为“MyDB”的特性“name”时使用“ReleaseSQLServer”。
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<system.web>
<!--
在下例中“Replace”转换将替换
web.config 文件的整个 <customErrors> 节。
请注意,由于
在 <system.web> 节点下仅有一个 customErrors 节因此不需要使用“xdt:Locator”特性。
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 有关使用 web.config 转换的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
在下例中“SetAttributes”转换将更改
“connectionString”的值以仅在“Match”定位器
找到值为“MyDB”的特性“name”时使用“ReleaseSQLServer”。
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<!--
在下例中“Replace”转换将替换
web.config 文件的整个 <customErrors> 节。
请注意,由于
在 <system.web> 节点下仅有一个 customErrors 节因此不需要使用“xdt:Locator”特性。
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>

20
Uploader/Web.config Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<!--
有关如何配置 ASP.NET 应用程序的详细信息,请访问
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<!--
有关 web.config 更改的说明,请参见 http://go.microsoft.com/fwlink/?LinkId=235367。
可在 <httpRuntime> 标记上设置以下特性。
<system.Web>
<httpRuntime targetFramework="4.5" />
</system.Web>
-->
<system.web>
<compilation debug="true" targetFramework="4.5"/>
<httpRuntime/>
<pages controlRenderingCompatibilityVersion="4.0"/>
</system.web>
</configuration>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resumables />

62
Uploader/index.aspx Normal file
View File

@@ -0,0 +1,62 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="index.aspx.cs" Inherits="HTML5Uploader.index" %>
<%@ Register Assembly="Html5Uploader" Namespace="Html5Uploader.Controls" TagPrefix="cc1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script src="Scripts/jquery-2.1.1.min.js"></script>
<%--<script src="Scripts/Uploader.release.min.js"></script>--%>
<%--<script src="Scripts/Uploader.min.js"></script>--%>
<%--<script src="Scripts/Uploader.js"></script>--%>
<script>
var prog;
function errorhandler(file, args)
{
alert("args.message=" + args.message + ",invalidType=" + file.invalidType)
//if (args.type == Uploader.ErrorType.UserAbort)
//{
//}
args.cancel = true;
}
function createProgress(file, args) {
var s = prog = this;
prog.file = file;
args.view = $(document.createElement("div")).appendTo("body").append("<h2>" + file.name + "</h2><p>size:" + Uploader.SizeToString(file.size) + " <span></span></p> <progress></progress><a href='javascript:' class='pause'>pause</a> <a href='javascript:' class='proceed'>proceed</a> <a href='javascript:' class='cancel'>cancel</a>");
args.view.find("a").click(function () {
var a = $(this);
if (a.hasClass("pause")) {
s.pause();
}
else if (a.hasClass("proceed"))
{ s.proceed();}
else if (a.hasClass("cancel"))
{ s.cancel(); }
});
}
</script>
</head>
<body>
<form id="form1" runat="server">
<cc1:Html5UploaderClient ID="Html5Uploader1" RegisterScript="true" Url="Handler1.ashx" Dragable="true" BlobSize="500kb"
MaxQueue="3" Placeholder="#btnSeletor" runat="server">
<ViewTemplate>
<a href="javascript:" id="btnSeletor" >select files</a>
</ViewTemplate>
<ClientEvents>
<cc1:ClientEvent EventName="error" Handle="errorhandler" />
<cc1:ClientEvent EventName="createProgress" Handle="createProgress" />
<%-- <cc1:ClientEvent EventName="validate" Handle="function(sender,arg){/* code ....*/}" />--%>
</ClientEvents>
</cc1:Html5UploaderClient>
</form>
</body>
</html>

17
Uploader/index.aspx.cs Normal file
View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace HTML5Uploader
{
public partial class index : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
}

33
Uploader/index.aspx.designer.cs generated Normal file
View File

@@ -0,0 +1,33 @@
//------------------------------------------------------------------------------
// <自动生成>
// 此代码由工具生成。
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </自动生成>
//------------------------------------------------------------------------------
namespace HTML5Uploader {
public partial class index {
/// <summary>
/// form1 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
/// <summary>
/// Html5Uploader1 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::Html5Uploader.Controls.Html5UploaderClient Html5Uploader1;
}
}

32
Uploader/index.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>超大文件上传</title>
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=1.0, user-scalable=no" />
<script src="Scripts/jquery-2.1.1.min.js"></script>
<script src="Scripts/Uploader.js"></script>
<!--<script src="Scripts/Uploader.min.js"></script>-->
<!--<script src="Scripts/Uploader.release.js"></script>-->
<!--<script src="Scripts/Uploader.release.min.js"></script>-->
</head>
<body>
<br />
<a href="#" id="btn">select files</a><br />
<input id="m" type="file" />
<a href="javascript:" id="up">upload</a>
<script>
$("#up").click(function () {
$("#m").asyncUploadFiles({ url: "Handler1.ashx" }, { complete: function (f,e) { alert(f.name+"上传已经完成!") }});
});
var uploader = new Uploader({
placeholder: "#btn", url: "Handler1.ashx"//,accept:"image/*",types:".jpg;.gif;.png",limitSize:1024*1024*50
, dragable: true//,dragContainer:$("#kk")
}, { error: function (file, args) { alert("message:" + args.message + ",type:" + args.type); args.cancel = true; } });
Uploader();
//var dd = new Uploader({ url: "/dd/dd" });
//dd.on();
</script>
</body>
</html>

4
Uploader/packages.config Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="jQuery" version="2.1.1" targetFramework="net45" />
</packages>