浏览代码

同步前端修改

wkeyuan 3 年之前
父节点
当前提交
c22560c6c3
共有 76 个文件被更改,包括 10742 次插入35 次删除
  1. 3 3
      src/main/resources/application-dev.yml
  2. 1 1
      src/main/resources/static/index.html
  3. 0 0
      src/main/resources/static/static/css/app.87037a1e635196120cdebcd7ffa6aa29.css
  4. 0 0
      src/main/resources/static/static/css/app.87037a1e635196120cdebcd7ffa6aa29.css.map
  5. 0 0
      src/main/resources/static/static/css/app.efd3ca44b025e10cf83d84b2339a4804.css
  6. 0 0
      src/main/resources/static/static/css/app.efd3ca44b025e10cf83d84b2339a4804.css.map
  7. 64 0
      src/main/resources/static/static/diaowen/answer-m.html
  8. 66 1
      src/main/resources/static/static/diaowen/answer-p.html
  9. 18 18
      src/main/resources/static/static/diaowen/css/design-survey.css
  10. 37 0
      src/main/resources/static/static/diaowen/css/survey-common.css
  11. 79 3
      src/main/resources/static/static/diaowen/design.html
  12. 二进制
      src/main/resources/static/static/diaowen/images/toolbar.png
  13. 180 0
      src/main/resources/static/static/diaowen/js/common/ans-common.js
  14. 1 1
      src/main/resources/static/static/diaowen/js/common/common.js
  15. 20 0
      src/main/resources/static/static/diaowen/js/dw/an/ans-m-data.js
  16. 17 2
      src/main/resources/static/static/diaowen/js/dw/an/ans-m.js
  17. 25 1
      src/main/resources/static/static/diaowen/js/dw/an/ans-p-data.js
  18. 5 2
      src/main/resources/static/static/diaowen/js/dw/an/ans-p.js
  19. 18 0
      src/main/resources/static/static/diaowen/js/dw/design-data.js
  20. 143 3
      src/main/resources/static/static/diaowen/js/dw/dwsurvey-design.js
  21. 15 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/CONTRIBUTING.md
  22. 21 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/LICENSE.txt
  23. 107 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/README.md
  24. 211 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/angularjs.html
  25. 226 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/basic-plus.html
  26. 136 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/basic.html
  27. 16 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/bower-version-update.js
  28. 64 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/bower.json
  29. 75 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/cors/postmessage.html
  30. 24 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/cors/result.html
  31. 21 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery-ui-demo-ie8.css
  32. 67 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery-ui-demo.css
  33. 22 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-noscript.css
  34. 17 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-ui-noscript.css
  35. 57 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-ui.css
  36. 37 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload.css
  37. 15 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/style.css
  38. 二进制
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/img/loading.gif
  39. 二进制
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/img/progressbar.gif
  40. 255 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/index.html
  41. 252 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/jquery-ui.html
  42. 101 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/app.js
  43. 126 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/cors/jquery.postmessage-transport.js
  44. 89 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/cors/jquery.xdr-transport.js
  45. 437 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-angular.js
  46. 113 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-audio.js
  47. 326 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-image.js
  48. 161 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-jquery-ui.js
  49. 178 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-process.js
  50. 714 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-ui.js
  51. 125 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-validate.js
  52. 113 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-video.js
  53. 1486 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload.js
  54. 224 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.iframe-transport.js
  55. 75 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/main.js
  56. 572 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/vendor/jquery.ui.widget.js
  57. 55 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/package.json
  58. 12 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/app.yaml
  59. 361 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/app/main.go
  60. 二进制
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/static/favicon.ico
  61. 2 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/static/robots.txt
  62. 17 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/app.yaml
  63. 204 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/main.py
  64. 二进制
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/static/favicon.ico
  65. 2 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/static/robots.txt
  66. 38 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/Dockerfile
  67. 1411 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/UploadHandler.php
  68. 6 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/docker-compose.yml
  69. 15 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/index.php
  70. 172 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/test/index.html
  71. 1292 0
      src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/test/test.js
  72. 0 0
      src/main/resources/static/static/js/app.86a8f295728ae093d34a.js
  73. 0 0
      src/main/resources/static/static/js/app.86a8f295728ae093d34a.js.map
  74. 0 0
      src/main/resources/static/static/js/app.ba05fbe971394f479030.js
  75. 0 0
      src/main/resources/static/static/js/app.ba05fbe971394f479030.js.map
  76. 0 0
      src/main/resources/static/static/js/manifest.2ae2e69a05c33dfc65f8.js.map

+ 3 - 3
src/main/resources/application-dev.yml

@@ -31,9 +31,9 @@ dwsurvey:
       encodingAESKey:
   # 产品版本号信息,V5-代表最新的前后端分离版本
   version:
-    info: DWSurvey OSS V5.2.1 Boot
-    number: OSS V5.2.1
-    built: 2021/12/31
+    info: DWSurvey OSS V5.2.2 Boot
+    number: OSS V5.2.2
+    built: 2022/01/20
 # 服务占用的端口号
 server:
   port: 8080

+ 1 - 1
src/main/resources/static/index.html

@@ -1 +1 @@
-<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link rel="shortcut icon" href=static/diaowen/images/favicon.ico type=image/x-icon><title>DWSurvey-调问开源问卷-社区版</title><link href=/static/css/app.87037a1e635196120cdebcd7ffa6aa29.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.2ae2e69a05c33dfc65f8.js></script><script type=text/javascript src=/static/js/vendor.f03de514a6e6e9148c3a.js></script><script type=text/javascript src=/static/js/app.ba05fbe971394f479030.js></script></body></html>
+<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link rel="shortcut icon" href=static/diaowen/images/favicon.ico type=image/x-icon><title>DWSurvey-调问开源问卷-社区版</title><link href=/static/css/app.efd3ca44b025e10cf83d84b2339a4804.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.2ae2e69a05c33dfc65f8.js></script><script type=text/javascript src=/static/js/vendor.f03de514a6e6e9148c3a.js></script><script type=text/javascript src=/static/js/app.86a8f295728ae093d34a.js></script></body></html>

文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/css/app.87037a1e635196120cdebcd7ffa6aa29.css


文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/css/app.87037a1e635196120cdebcd7ffa6aa29.css.map


文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/css/app.efd3ca44b025e10cf83d84b2339a4804.css


文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/css/app.efd3ca44b025e10cf83d84b2339a4804.css.map


+ 64 - 0
src/main/resources/static/static/diaowen/answer-m.html

@@ -12,6 +12,11 @@
   <link rel="stylesheet" type="text/css" href="css/answer-m.css" />
   <script type="text/javascript" src="js/plugs/jquery-ui-1.10.3.custom/js/jquery-1.10.1.js"></script>
   <script type="text/javascript" src="js/plugs/jquery-ui-1.10.3.custom/js/jquery-ui-1.10.3.custom.js"></script>
+  <link rel="stylesheet" href="js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload.css">
+  <link rel="stylesheet" href="js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-ui.css">
+  <script src="js/plugs/jQuery-File-Upload-9.19.2/js/vendor/jquery.ui.widget.js"></script>
+  <script src="js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload.js"></script>
+  <script src="js/plugs/jQuery-File-Upload-9.19.2/js/jquery.iframe-transport.js"></script>
   <script type="text/javascript" src="js/plugs/laydate/laydate.js"></script>
   <script type="text/javascript" src="js/common/ans-common.js"></script>
   <script type="text/javascript" src="js/common/common.js"></script>
@@ -296,6 +301,65 @@
         </div>
       </li>
     </ul>
+    <ul id="uploadFileQuModel">
+      <li class="li_surveyQuItemBody" >
+        <div class="surveyQuItemBody">
+          <div class="initLine"></div>
+          <div class="quInputCase" style="display: none;">
+            <input type="hidden" class="quType" value="UPLOADFILE">
+            <input type="hidden" class="quId" value="${en.id }">
+            <input type="hidden" class="orderById" value="${en.orderById }"/>
+            <input type="hidden" class="isRequired" value="${en.isRequired }">
+            <input type="hidden" class="checkType" value="${en.checkType }">
+            <input type="hidden" class="answerTag" value="0" >
+            <input type="hidden" class="paramInt01" value="${en.paramInt01 }">
+            <input type="hidden" class="paramInt02" value="${en.paramInt02 }">
+            <input type="hidden" class="randOrder" value="${en.randOrder }">
+            <div class="quLogicInputCase"></div>
+          </div>
+          <div class="surveyQuItem">
+            <div class="surveyQuItemContent">
+              <div class="quCoTitle">
+                <span class="quTitleNum">${i.count }、</span>
+                <span class="quTitleText">${en.quTitle}</span>
+              </div>
+              <div class="quCoItem"><ul>
+                <li class="quCoItemUlLi">
+                  <div class="quFillblankItem">
+                    <div class="uploadFileTypeNoteSpan" style="color: grey;line-height: 23px;padding-bottom: 5px;font-size: 12px;">
+                      <span class="uploadFileTypeNote" ></span>
+                      <span>单个文件最大支持 <label class="uploadFileMaxSize">${en.paramInt02}</label> M</span>
+                    </div>
+                    <div class="upFileDiv">
+
+                    </div>
+
+                    <div>
+                      <!-- The fileinput-button span is used to style the file input field as button -->
+                      <span class="sbtn sbtn_0 fileinput-button">
+																	<span>上传文件</span>
+																	<input class="fileupload" type="file" name="file" multiple>
+																	<input class="fileuploadPath" type="hidden" uphidinputname="qu_${en.quType }_${en.id }" >
+																</span>
+                      <!-- The global progress bar -->
+                      <div class="progress" style="display: none;margin-top: 10px;">
+                        <div class="progress-bar progress-bar-success"></div>
+                      </div>
+                      <!-- The container for the uploaded files -->
+                      <div class="files"></div>
+                    </div>
+                    <input type="hidden" class="answerTag" value="0" >
+                    <div class="dwComEditMenuBtn" ></div>
+                  </div>
+                </li>
+              </ul>
+              </div>
+            </div>
+
+          </div>
+        </div>
+      </li>
+    </ul>
     <ul id="dwSubmitModel">
       <li class="li_surveyQuItemBody surveySubmitBody" style="padding-top:20px;"  >
         <div class="surveyQuItemBody">

+ 66 - 1
src/main/resources/static/static/diaowen/answer-p.html

@@ -2,7 +2,7 @@
 <html>
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-  <title></title>
+  <title>答卷页面</title>
   <link href="js/plugs/jquery-ui-1.10.3.custom/css/mycss/jquery-ui-1.10.3.custom.css" rel="stylesheet" type="text/css" />
   <link rel="stylesheet" type="text/css" href="css/preview-dev.css" />
   <link rel="stylesheet" type="text/css" href="js/plugs/colpick-jQuery/css/colpick.css" />
@@ -12,6 +12,11 @@
   <script type="text/javascript" src="js/plugs/jquery-ui-1.10.3.custom/js/jquery-1.10.1.js"></script>
   <script type="text/javascript" src="js/plugs/jquery-ui-1.10.3.custom/js/jquery-ui-1.10.3.custom.js"></script>
   <script type="text/javascript" src="js/plugs/colpick-jQuery/js/colpick.js"></script>
+  <link rel="stylesheet" href="js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload.css">
+  <link rel="stylesheet" href="js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-ui.css">
+  <script src="js/plugs/jQuery-File-Upload-9.19.2/js/vendor/jquery.ui.widget.js"></script>
+  <script src="js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload.js"></script>
+  <script src="js/plugs/jQuery-File-Upload-9.19.2/js/jquery.iframe-transport.js"></script>
   <script type="text/javascript" src="js/plugs/laydate/laydate.js"></script>
   <script type="text/javascript" src="js/common/ans-common.js"></script>
   <script type="text/javascript" src="js/common/common.js"></script>
@@ -352,6 +357,66 @@
       </li>
     </ul>
 
+    <ul id="uploadFileQuModel">
+      <li class="li_surveyQuItemBody" >
+        <div class="surveyQuItemBody">
+          <div class="initLine"></div>
+          <div class="quInputCase" style="display: none;">
+            <input type="hidden" class="quType" value="UPLOADFILE">
+            <input type="hidden" class="quId" value="${en.id }">
+            <input type="hidden" class="orderById" value="${en.orderById }"/>
+            <input type="hidden" class="isRequired" value="${en.isRequired }">
+            <input type="hidden" class="checkType" value="${en.checkType }">
+            <input type="hidden" class="answerTag" value="0" >
+            <input type="hidden" class="paramInt01" value="${en.paramInt01 }">
+            <input type="hidden" class="paramInt02" value="${en.paramInt02 }">
+
+            <input type="hidden" class="randOrder" value="${en.randOrder }">
+            <div class="quLogicInputCase"></div>
+          </div>
+          <div class="surveyQuItem">
+            <div class="surveyQuItemContent">
+              <div class="quCoTitle">
+                <div class="quCoNum">${i.count }、</div>
+                <div class="editAble quCoTitleEdit" >${en.quTitle}</div>
+              </div>
+              <div class="quCoItem"><ul>
+                <li class="quCoItemUlLi">
+                  <div class="quFillblankItem">
+                    <div class="uploadFileTypeNoteSpan" style="color: grey;line-height: 23px;padding-bottom: 5px;">
+                      <span class="uploadFileTypeNote" ></span>
+                      <span>单个文件最大支持 <label class="uploadFileMaxSize">${en.paramInt02}</label> M</span>
+                    </div>
+                    <div class="upFileDiv"></div>
+                    <div>
+                      <!-- The fileinput-button span is used to style the file input field as button -->
+                      <span class="sbtn sbtn_0 fileinput-button">
+                        <span>上传文件</span>
+                        <input class="fileupload" type="file" name="file" multiple>
+                        <input class="fileuploadPath" type="hidden" uphidinputname="qu_${en.quType }_${en.id }" >
+                      </span>
+                      <!-- The global progress bar -->
+                      <div class="progress" style="display: none;margin-top: 10px;">
+                        <div class="progress-bar progress-bar-success"></div>
+                      </div>
+                      <!-- The container for the uploaded files -->
+                      <div class="files"></div>
+                    </div>
+
+                    <input type="hidden" class="answerTag" value="0" >
+
+                    <div class="dwComEditMenuBtn" ></div>
+                  </div>
+                </li>
+              </ul>
+              </div>
+            </div>
+
+          </div>
+        </div>
+      </li>
+    </ul>
+
     <ul id="dwSubmitModel">
       <li class="li_surveyQuItemBody surveySubmitBody" >
         <div class="surveyQuItemBody">

+ 18 - 18
src/main/resources/static/static/diaowen/css/design-survey.css

@@ -190,7 +190,7 @@ textarea{
 	display: inline;
 }
 #toolsBashQu{
-	width: 431px;
+	width: 491px;
 }
 #toolsChenQu{
 	width: 251px;
@@ -231,7 +231,7 @@ textarea{
 	/* border: 1px solid #cc3333; */
 }
 .toolbars ul li .dwToolbar_icon{
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	width: 50px;
 	height: 60px;
 	margin: 0px;
@@ -452,7 +452,7 @@ textarea{
 #dateQuModel:hover .dwToolbar_icon,#dateQuModel.hover .dwToolbar_icon{
 	background-position: -626px -320px;
 }
-
+#uploadFileQuModel .dwToolbar_icon{background-position:-1135px -6px}#uploadFileQuModel.hover .dwToolbar_icon,#uploadFileQuModel:hover .dwToolbar_icon{background-position:-1135px -77px}
 #publishBtn .dwToolbar_icon{
 	width:70px;
 	height:39px;
@@ -770,7 +770,7 @@ textarea{
 	width: 40px;
 }
 .surveyQuItemLeftToolsUl li .dwQuIcon{
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	width: 23px;
 	height: 23px;
 	margin: 0px auto;
@@ -814,7 +814,7 @@ li.dwQuLogic  .dwQuIcon  .quLogicInfo{
 	display: none;
 }
 .quLogicData .dwQuIcon{
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	background-position: -279px -178px;
 	width: 23px;
 	height: 23px;
@@ -855,7 +855,7 @@ li.dwQuLogic  .dwQuIcon  .quLogicInfo{
 	margin:0px;
 }
 .surveyQuItemRightToolsUl li .dwQuIcon{
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	width: 23px;
 	height: 23px;
 }
@@ -989,17 +989,17 @@ li.dwQuLogic  .dwQuIcon  .quLogicInfo{
 	width: 40px;
 }
 .surveyQuItemContent .quCoBottomTools ul li .dwQuIcon{
-	/* background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat; */
+	/* background: transparent url("../images/toolbar.png") 0px 0px no-repeat; */
 	width: 25px;
 	height: 25px;
 	margin: 0px auto;
 }
 li.addOption .dwQuIcon,li.addColumnOption .dwQuIcon,li.addRowOption .dwQuIcon{
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	background-position: -620px -153px;
 }
 li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption .dwQuIcon{
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	background-position: -658px -153px;
 }
 .surveyQuItemContent .quCoBottomTools ul li:hover{
@@ -1097,7 +1097,7 @@ li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption
 .dwComEditOptionUl li .dwQuIcon{
 	width: 30px;
 	height: 26px;
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 }
 .dwComEditOptionUl li.dwOptionUp .dwQuIcon{
 	background-position:-468px -150px;
@@ -1114,7 +1114,7 @@ li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption
 	right: -32px;
 	top:-1px;
 	border: 1px solid #98C5C3;
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	cursor: pointer;
 	background-color: #DBE5F1;
 }
@@ -1234,7 +1234,7 @@ li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption
 .dwCommonInputMenu .dwComEditMenuBtn{
 	position: absolute;
 	border: 1px solid #98C5C3;
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	cursor: pointer;
 	background-color: #DBE5F1;
 }
@@ -1326,7 +1326,7 @@ li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption
 	float:right;
 	width: 28px;
 	height: 28px;
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	background-position:-494px -150px;
 	cursor: pointer;
 }
@@ -1441,14 +1441,14 @@ li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption
 		width: 25px;
 		height: 25px;
 		margin: 0px auto;
-		background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+		background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 		background-position: -620px -153px;
 }
 .dialogRemoveLogic{
 		width: 23px;
 		height: 23px;
 		margin: 0px auto;
-		background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+		background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 		background-position: -690px -152px;
 		cursor: pointer;
 }
@@ -1492,7 +1492,7 @@ li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption
 .quFillblankItem .dwFbMenuBtn{
 	position: absolute;
 	border: 1px solid #98C5C3;
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat;
 	cursor: pointer;
 	background-color: #DBE5F1;
 	display: none;
@@ -1599,7 +1599,7 @@ li.addMoreOption .dwQuIcon,li.addMoreColumnOption .dwQuIcon,li.addMoreRowOption
 }
 /**jquery ui dialog**/
 .ui-icon-closethick {
-	background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat! important;
+	background: transparent url("../images/toolbar.png") 0px 0px no-repeat! important;
 	background-position: -502px -155px! important;
 }
 #editDialogCenter{
@@ -1673,7 +1673,7 @@ table.quCoChenTable tr td label{
 	text-align: center;
 }
 .surveyQuItemContent .quCoRightTools ul li .dwQuIcon{
-	/* background: transparent url("../images/toolbar-oss@1x.png") 0px 0px no-repeat; */
+	/* background: transparent url("../images/toolbar.png") 0px 0px no-repeat; */
 	width: 25px;
 	height: 25px;
 	margin: 0px auto;

+ 37 - 0
src/main/resources/static/static/diaowen/css/survey-common.css

@@ -4,3 +4,40 @@ select {
   height: 40px;
   color: #666;
 }
+.upFileDiv .upAppend {
+  margin-bottom: 8px;
+  border: 1px solid grey;
+  padding: 6px;
+}
+.upFileDiv .upAppend a {
+  float: right;
+  margin-right: 10px;
+}
+.sbtn{
+  background: #0887d2;
+  width: 88px;
+  height: 30px;
+  color: #777;
+  background-position: 0 -240px;
+  font-size: 12px;
+  border: 0;
+  cursor: pointer;
+  display: inline-block;
+  zoom: 1;
+  line-height: 30px;
+  text-align: center;
+  text-decoration: none;
+  font-family: "Hiragino Sans GB","Microsoft YaHei","微软雅黑",tahoma,arial,simsun,"宋体";
+  background: rgb(79, 139, 255);
+}
+.sbtn_0{
+  background-position: 0 -200px;
+  background: white;
+  border: 1px dashed grey;
+}
+.sbtn_0:hover{
+  background-position: 0 -200px;
+  color: #fff;
+  background: dodgerblue;
+  border-color: dodgerblue;
+}

+ 79 - 3
src/main/resources/static/static/diaowen/design.html

@@ -152,7 +152,8 @@
 
                         <input type="hidden" name="contactsAttr" value="0">
                         <input type="hidden" name="contactsField" value="0">
-
+                        <input type="hidden" name="paramInt01" value="0">
+                        <input type="hidden" name="paramInt02" value="0">
                         <div class="quLogicInputCase">
                           <input type="hidden" name="quLogicItemNum" value="0">
                         </div>
@@ -590,6 +591,74 @@
                     </div>
                   </div>
                 </li>
+                <li id="uploadFileQuModel">
+                  <div class="dwToolbar_icon dwsurveyfont icon-dwsurvey-shangchuan"></div>
+                  <div class="dwQuTypeModel">
+                    <div class="surveyQuItemBody quDragBody">
+                      <div class="initLine"></div>
+                      <div class="quInputCase" style="display: none;">
+                        <input type="hidden" name="quType" value="UPLOADFILE" >
+                        <input type="hidden" name="quId" value="">
+                        <input type="hidden" name="orderById" value="0"/>
+                        <input type="hidden" name="saveTag" value="0">
+                        <input type="hidden" name="hoverTag" value="0">
+                        <input type="hidden" name="isRequired" value="1">
+                        <input type="hidden" name="hv" value="2">
+                        <input type="hidden" name="randOrder" value="0">
+                        <input type="hidden" name="cellCount" value="0">
+                        <input type="hidden" name="checkType" value="NO">
+
+                        <input type="hidden" name="answerInputWidth" value="300">
+                        <input type="hidden" name="answerInputRow" value="1">
+
+                        <input type="hidden" name="contactsAttr" value="0">
+                        <input type="hidden" name="contactsField" value="0">
+
+                        <input type="hidden" name="paramInt01" value="1">
+                        <input type="hidden" name="paramInt02" value="10">
+
+                        <div class="quLogicInputCase">
+                          <input type="hidden" name="quLogicItemNum" value="0">
+                        </div>
+                      </div>
+                      <div class="surveyQuItem">
+                        <div class="surveyQuItemLeftTools">
+                          <ul class="surveyQuItemLeftToolsUl">
+                            <li title="移动排序" class="dwQuMove"><div class="dwQuIcon"></div></li>
+                            <li title="设置" class="dwQuSet"><div class=dwQuIcon></div></li>
+                            <li title="逻辑" class="dwQuLogic"><div class="dwQuIcon"><div class="quLogicInfo"></div></div></li>
+                            <li title="删除" class="dwQuDelete"><div class="dwQuIcon"></div></li>
+                          </ul>
+                        </div>
+                        <div class="surveyQuItemRightTools">
+                          <ul class="surveyQuItemRightToolsUl">
+                            <li class="questionUp"><div class="dwQuIcon"></div></li>
+                            <li class="questionDown"><div class="dwQuIcon"></div></li>
+                          </ul>
+                        </div>
+                        <div class="surveyQuItemContent">
+                          <div class="quCoTitle">
+                            <div class="quCoNum">1、</div>
+                            <div class="editAble quCoTitleEdit" >请上传文件?</div>
+                            <input type="hidden" name="quTitleSaveTag" value="0">
+                          </div>
+                          <div class="quCoQuNote">
+                            <div class="editAble quCoNoteEdit" ></div>
+                          </div>
+                          <div class="quCoItem"><ul>
+                            <li class="quCoItemUlLi">
+                              <!-- <input type="text" style="width:200px;padding:5px;"> -->
+                              <div class="quFillblankItem">
+                                <input type="file" >
+                              </div>
+                            </li>
+                          </ul>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </li>
               </ul>
             </div>
             <div class="tooltext">基本题型</div>
@@ -1508,13 +1577,20 @@
               </select>
               <span class="option_range_3" style="display:none;"><input type="text" name="setCellCount"  size="2" value="3" class="" >&nbsp;列</span>
             </li>
-            <!-- <li class="minNumLi">最少选&nbsp;<input type="text" size="3" name="minNum">&nbsp;项 </li>
-            <li class="maxNumLi">最多选&nbsp;<input type="text" size="3" name="maxNum">&nbsp;项 </li> -->
+            <li class="minNumLi">最少选&nbsp;<input type="text" size="3" name="minNum" value="0">&nbsp;项 </li>
+            <li class="maxNumLi">最多选&nbsp;<input type="text" size="3" name="maxNum" value="0">&nbsp;项 </li>
             <li class="minMaxLi">
               <span class="minSpan"><label class="lgleftLabel">&nbsp;最低分</label>&nbsp;<input class="minNum" value="1"  type="text" size="2" >&nbsp; <label class="lgRightLabel">分</label></span>&nbsp;&nbsp;
               <span class="maxSpan"><label class="lgLeftLabel">最高分</label>&nbsp;<input class="maxNum"  value="5"  type="text" size="2" >&nbsp;<label class="lgRightLabel">分</label> </span>
             </li>
             <li class="scoreMinMax">&nbsp;&nbsp;<label>最高分</label>&nbsp;<select class="maxScore"  ><option value="5">5分</option><option value="10">10分</option></select>&nbsp; </li>
+            <li class="fileTypeExtsLi">
+              <div><label>&nbsp;上传文件类型</label>&nbsp;
+                <select class="fileTypeExts"  ><option value="0">不限</option><option value="1">图片文件</option><option value="2">文本文件</option></select>&nbsp;<br/>
+              </div>
+              <div style="margin-top: 8px;"><label>&nbsp;上传附件数</label>&nbsp;&nbsp;<label><input type="text" class="uploadNum" size="5" value="0"  >&nbsp;&nbsp;0&nbsp;表示不限制</label></div>
+              <div style="margin-top: 8px;"><label>&nbsp;单个文件最大支持</label>&nbsp;&nbsp; <input class="maxSize"  value="10"  type="text" size="5" ><label>&nbsp;M</label></div>
+            </li>
           </ul>
           <div class="dwQuDialogBtnCon" ><input type="button" value="保存" class="quDialogBtn" id="dwDialogQuSetSave"/></div>
         </div>

二进制
src/main/resources/static/static/diaowen/images/toolbar.png


+ 180 - 0
src/main/resources/static/static/diaowen/js/common/ans-common.js

@@ -139,3 +139,183 @@ function checkoutData(checkType, value) {
     }
     return validateStatus;
 }
+
+
+var upEventIndex = 0;
+function wwwUpload(){
+  var ctx = $("#ctx").val();
+  var url = '/api/dwsurvey/up/up-file-wb.do';
+  //alert('data');
+  $("#dwSurveyQuContentAppUl .fileupload").unbind();
+  $("#dwSurveyQuContentAppUl .fileupload").fileupload({
+    url: url,
+    // maxFileCount:1,
+    dataType: 'json',
+    // forceIframeTransport: true,
+    // autoUpload:true,
+//  formData: {"safe":"webInf"},
+    add: function(e, data) {
+
+      var thObj = $(this);
+      showUpFileMsg(thObj,"准备上传...");
+
+      var surveyQuItemBody = $(this).parents(".surveyQuItemBody");
+      var paramInt01 = surveyQuItemBody.find(".paramInt01").val();
+      var paramInt02 = surveyQuItemBody.find(".paramInt02").val();
+      var randOrder = surveyQuItemBody.find(".randOrder").val();
+
+      var upAppend=surveyQuItemBody.find(".upFileDiv .upAppend");
+      if(upAppend[0] && randOrder>0 && upAppend.size()>=randOrder ){
+        // alert("最多只能上传"+randOrder+"个附件");
+        showUpFileMsg(thObj,"最多只能上传"+randOrder+"个附件");
+        return ;
+      }
+
+      if(paramInt01==1){
+        /*
+        var acceptFileTypes = /^image\/(gif|jpe?g|png)$/i;
+        //文件类型判断
+        if(data.originalFiles[0]['type'].length && !acceptFileTypes.test(data.originalFiles[0]['type'])) {
+            alert("上传文件类型不对,请上传图片文件!");
+            return ;
+        }
+         */
+        var acceptFileTypes = /(\.|\/)(gif|jpg|jpeg|png|bmp)$/i;
+        //文件类型判断
+        if(!acceptFileTypes.test(data.originalFiles[0].name)) {
+          // alert("上传文件类型不对,请上传图片文件!");
+          showUpFileMsg(thObj,"上传文件类型不对,请上传图片文件!");
+          return ;
+        }
+      }
+
+      if(paramInt01==2){
+//      var acceptFileTypes = /\/(txt|doc?x|xls?x|ppt?x|pdf|xml)$/i;
+        var acceptFileTypes = /(\.|\/)(txt|doc|docx|xls|xlsx|ppt|pptx|pdf|xml)$/i;
+        //文件类型判断
+        if(!acceptFileTypes.test(data.originalFiles[0].name)) {
+          // alert("上传文件类型不对,请上传文本文件!");
+          showUpFileMsg(thObj,"上传文件类型不对,请上传文本文件!");
+          return ;
+        }
+      }
+
+      //文件大小判断
+      if(paramInt02!=null && paramInt02!=""){
+        var maxSize = 1024*1024*paramInt02;
+        if(data.originalFiles[0]['size'] > maxSize) {
+          // alert("文件大小超出限制,最大支持"+paramInt02+"M");
+          showUpFileMsg(thObj,"文件大小超出限制,最大支持"+paramInt02+"M");
+          return;
+        }
+      }
+      /*
+      var url = getUrl(data.files[0]);
+      surveyQuItemBody.find(".quFillblankItem").prepend("<label class='upImgLabel' ><img class='upAppend' src='${ctx}"+url+"' height='150' >&nbsp;<a href='' ><i class='fa fa-times' aria-hidden='true'></i></a>" +
+              "<input type='hidden' class='upFileName' value='"+data.files[0].name+"' />"+
+              "<input type='hidden' class='upFilePath' value='' />"+
+              "</label>");
+      */
+      data.submit();
+
+      showUpFileMsg(thObj,"上传中...");
+    },
+    change: function (e, data) {
+      //alert("change:"+data.files.length);
+      /*
+       $.each(data.files, function (index, file) {
+       alert('Selected file: ' + file.name);
+       console.log(file);
+       });
+       */
+    },
+    done: function (e, data) {
+      // alert(JSON.stringify(data));
+//        "{\"success\":\"true\",\"filename\":\"粉刷.jpeg  \",\"location\":\"/file/images/粉刷.jpeg\"}"
+//             var result = data.result[0].body ? data.result[0].body.innerHTML : data.result;
+//             result = JSON.parse(result);
+//             var result = eval("("+data.result+")");
+//             var location = result.location;
+//             var fileName = result.filename;
+
+      var location = null;
+      var fileName = null;
+      var httpResult = data.result;
+      var resultCode = httpResult.resultCode;
+      var resultData = httpResult.data;
+      if(resultCode==200){
+        //实际只会有一条
+        $.each(resultData,function (i,item){
+          location = item.location;
+          fileName = item.filename;
+        });
+      }
+
+      //如果是图片,则取回进行显示
+      var surveyQuItemBody = $(this).parents(".surveyQuItemBody");
+      var paramInt01 = surveyQuItemBody.find(".paramInt01").val();
+      if(false){
+//      surveyQuItemBody.find(".quFillblankItem .upAppend").remove();
+//      <label class='upImgLabel' ><img class='upAppend' src='' height='150' ><a href='' ><i class='fa fa-times' aria-hidden='true'></i></a></label>
+//             surveyQuItemBody.find(".quFillblankItem").prepend("<img class='upAppend' src='${ctx}"+location+"' height='150' style='margin-bottom:8px;border:1px solid grey;padding:6px;' />");
+        surveyQuItemBody.find(".quFillblankItem").prepend("<label class='upImgLabel' ><img class='upAppend' src='"+ctx+location+"' height='150' >&nbsp;<a href='' ><i class='fa fa-times' aria-hidden='true'></i></a></label>");
+        surveyQuItemBody.find("span.fileinput-button span").text("继续上传");
+        surveyQuItemBody.find(".fileuploadPath").val(location+"___"+fileName);
+      }else{
+        var fileuploadPathName = surveyQuItemBody.find(".fileuploadPath").attr("uphidinputname")+"_"+(upEventIndex++);
+        var fileSaveValue = location+"___"+fileName;
+//      surveyQuItemBody.find(".quFillblankItem .upAppend").remove();
+//      surveyQuItemBody.find(".quFillblankItem").prepend("<div class='upAppend' style='margin-bottom:8px;border:1px solid grey;padding:6px;' > 文件名称:"+fileName+" </div>");
+        surveyQuItemBody.find(".quFillblankItem .upFileDiv").prepend('<div class="upAppend" ><label style="overflow: auto;width: 95%;">文件名称:'+fileName+'</label><a href="#" class="removeUpFile" ><i class="fa fa-times" aria-hidden="true"></i></a>' +
+          '<input type="hidden" class="fileuploadSaveValue" name="'+fileuploadPathName+'" value="'+fileSaveValue+'" />' +
+          '</div>');
+        surveyQuItemBody.find("span.fileinput-button span").text("继续上传");
+//      surveyQuItemBody.find(".fileuploadPath").val(fileSaveValue);
+      }
+      bindUpEvent();
+      surveyQuItemBody.find(".answerTag").val(1);
+      var quCoItemUlLi = $(this).parents(".quCoItemUlLi");
+      quCoItemUlLi.find('.progress').fadeOut(3000);
+      //保存路径
+      var li_surveyQuItemBody = $(this).parents(".li_surveyQuItemBody");
+      runlogic(li_surveyQuItemBody,$(this));
+      validateCheck(surveyQuItemBody,false);
+      answerProgressbar(surveyQuItemBody);
+    },
+    progressall: function (e, data) {
+      var quCoItemUlLi = $(this).parents(".quCoItemUlLi");
+      var progress = parseInt(data.loaded / data.total * 100, 10);
+      quCoItemUlLi.find('.progress').show();
+      quCoItemUlLi.find('.progress .progress-bar').css(
+        'width',
+        progress + '%'
+      );
+      quCoItemUlLi.find('.progressAfter').remove();
+      quCoItemUlLi.find('.progress').after("<div class='progressAfter' style='font-size: 14px;color: dodgerblue;margin-top: 10px;'>上传进度:"+progress+"%</div>");
+    }
+  }).prop('disabled', !$.support.fileInput).parent().addClass($.support.fileInput ? undefined : 'disabled');
+}
+
+function showUpFileMsg(thObj,upMessage) {
+  var quCoItemUlLi = $(thObj).parents(".quCoItemUlLi");
+  var progress = quCoItemUlLi.find('.progress');
+  if(progress[0]){
+    quCoItemUlLi.find('.progressAfter').remove();
+    progress.show();
+    progress.after("<div class='progressAfter' style='font-size: 14px;color: dodgerblue;margin-top: 10px;'>"+upMessage+"</div>");
+  }
+}
+function bindUpEvent(){
+  $(".removeUpFile").unbind();
+  $(".removeUpFile").click(function(){
+    var surveyQuItemBody = $(this).parents(".li_surveyQuItemBody");
+    $(this).parents(".upAppend").remove();
+    runlogic(surveyQuItemBody,null);
+    validateCheck(surveyQuItemBody,false);
+    answerProgressbar(surveyQuItemBody);
+    var quId = surveyQuItemBody.find(".quId").val();
+    // removeLocalStorage("qu_UPLOADFILE_"+quId);
+    localStorageQu(surveyQuItemBody);
+    return false;
+  });
+}

+ 1 - 1
src/main/resources/static/static/diaowen/js/common/common.js

@@ -66,7 +66,7 @@ $(document).ready(function(){
       type: btypeInfo,
       pc: pc,
       prefix: prefix,
-      isMobile: pc !== "pc",
+      isMobile: pc !== "pc"
     };
   };
   $.answerPage = function(pageName,sid,callback) {

+ 20 - 0
src/main/resources/static/static/diaowen/js/dw/an/ans-m-data.js

@@ -42,6 +42,8 @@ function querySurveyAll(callback) {
               pageNo+=1;
             }else if(quType==="PARAGRAPH"){
               parseParagraph(item,pageNo);
+            }else if(quType === "UPLOADFILE"){
+              parseUploadfile(item,pageNo);
             }
           });
           parseSubmit(pageNo);
@@ -435,6 +437,24 @@ function parseParagraph(item,pageNo){
 
 }
 
+function parseUploadfile(item,pageNo){
+  var quModel = $("#uploadFileQuModel").html();
+  $("#dwSurveyQuContentAppUl").append(quModel);
+  var lastQuItemBody = $("#dwSurveyQuContentAppUl .li_surveyQuItemBody").last()
+  lastQuItemBody.find(".quDragBody").removeClass("quDragBody");
+  var quInputCase = lastQuItemBody.find(".quInputCase");
+  parseExtracted(quInputCase, item);
+  quLogicExtracted(lastQuItemBody, item, pageNo);
+  if(item.paramInt01===1){
+    lastQuItemBody.find(".uploadFileTypeNote").text("请上传后缀为.gif,.jpe,.jpeg,.png的图片");
+  }else if(item.paramInt01===2){
+    lastQuItemBody.find(".uploadFileTypeNote").text("请上传后缀为.txt,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.xml的文件");
+  }
+  lastQuItemBody.find(".uploadFileMaxSize").text(item.paramInt02);
+  var fileuploadPath = lastQuItemBody.find("input.fileuploadPath");
+  fileuploadPath.attr("uphidinputname","qu_"+item.quType+"_"+item.id);
+}
+
 function parseSubmit(pageNo){
   var quModel = $("#dwSubmitModel").html();
   $("#dwSurveyQuContentAppUl").append(quModel);

+ 17 - 2
src/main/resources/static/static/diaowen/js/dw/an/ans-m.js

@@ -32,6 +32,7 @@ $(document).ready(function(){
     if(!$("#preview_head_top")[0]){
       checkAnswerSurvey(sid);
     }
+    wwwUpload();
   });
 });
 
@@ -406,6 +407,18 @@ function sww(){
           dwQuInputLabel.addClass("checked");
           thObj.addClass("active");
         }
+        var checkeds = quItemBody.find("input[type='checkbox']:checked");
+        var paramInt02 = quItemBody.find(".paramInt02").val();
+        if(paramInt02>0){
+          if(checkeds[0]&&checkeds.size()>paramInt02){
+            dwQuInputLabel.removeClass("checked");
+            thObj.find("input[type='checkbox']").prop("checked",false);
+            thObj.removeClass("active");
+            alert("最多只支持选择"+paramInt02+"项内容!");
+            return false;
+          }
+        }
+
         runlogic(thObj.find("input[type='checkbox']"));
       }else if("MULTIFILLBLANK"===quType){
 
@@ -953,11 +966,11 @@ function sww(){
         validateStatus=quItemBody.find("input[type='checkbox']:checked")[0];
         var paramInt01 = quItemBody.find(".paramInt01").val();
         if(paramInt01>0){
-          /*var checkeds = quItemBody.find("input[type='checkbox']:checked");
+          var checkeds = quItemBody.find("input[type='checkbox']:checked");
           if(checkeds[0]&&checkeds.size()<paramInt01){
             errorMsg = "请保证最少选择"+paramInt01+"项内容";
             validateStatus = false;
-          }*/
+          }
         }
         if(validateStatus){
 //					isNote checkType isRequiredFill
@@ -1027,6 +1040,8 @@ function sww(){
           }
         }
 
+      }else if(quType === "UPLOADFILE"){
+        validateStatus=quItemBody.find(".fileuploadSaveValue")[0];
       }else if(quType==="submitSurveyBtn" || quType==="PARAGRAPH" || quType==="PAGETAG"){
         return true;
       }

+ 25 - 1
src/main/resources/static/static/diaowen/js/dw/an/ans-p-data.js

@@ -42,6 +42,8 @@ function querySurveyAll(callback) {
               pageNo+=1;
             }else if(quType==="PARAGRAPH"){
               parseParagraph(item,pageNo);
+            }else if(quType === "UPLOADFILE"){
+              parseUploadfile(item,pageNo);
             }
           });
           parseSubmit(pageNo);
@@ -81,9 +83,13 @@ function parseSurvey(data,tag){
   $("#id").val(data.id);
   $("#surveyId").val(data.id);
   $("#dwSurveyName").html(data.surveyName);
-  $("title").text($("#dwSurveyName").text());
   $("#dwSurveyNoteEdit").html(data.surveyDetail.surveyNote);
   $("#breakpoint1").val(data.surveyDetail.breakpoint1);
+  try{
+    $("title").text($("#dwSurveyName").text());
+  }catch (err){
+    document.title = $("#dwSurveyName").text();
+  }
 }
 
 
@@ -442,6 +448,24 @@ function parseParagraph(item,pageNo){
   quLogicExtracted(lastQuItemBody, item, pageNo);
 }
 
+function parseUploadfile(item,pageNo){
+  var quModel = $("#uploadFileQuModel").html();
+  $("#dwSurveyQuContentAppUl").append(quModel);
+  var lastQuItemBody = $("#dwSurveyQuContentAppUl .li_surveyQuItemBody").last()
+  lastQuItemBody.find(".quDragBody").removeClass("quDragBody");
+  var quInputCase = lastQuItemBody.find(".quInputCase");
+  parseExtracted(quInputCase, item);
+  quLogicExtracted(lastQuItemBody, item, pageNo);
+  if(item.paramInt01===1){
+    lastQuItemBody.find(".uploadFileTypeNote").text("请上传后缀为.gif,.jpe,.jpeg,.png的图片");
+  }else if(item.paramInt01===2){
+    lastQuItemBody.find(".uploadFileTypeNote").text("请上传后缀为.txt,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.xml的文件");
+  }
+  lastQuItemBody.find(".uploadFileMaxSize").text(item.paramInt02);
+  var fileuploadPath = lastQuItemBody.find("input.fileuploadPath");
+  fileuploadPath.attr("uphidinputname","qu_"+item.quType+"_"+item.id);
+}
+
 function parseSubmit(pageNo){
   var quModel = $("#dwSubmitModel").html();
   $("#dwSurveyQuContentAppUl").append(quModel);

+ 5 - 2
src/main/resources/static/static/diaowen/js/dw/an/ans-p.js

@@ -28,6 +28,7 @@ $(document).ready(function(){
   $.answerPage("p",sid,function(){
     querySurveyAll(function(){
       sww();
+      wwwUpload();
       if(!$("#preview_head_top")[0]){
         checkAnswerSurvey(sid);
       }
@@ -953,13 +954,13 @@ function validateCheck(quItemBody,isSubForm){
       var paramInt01 = quItemBody.find(".paramInt01").val();
 
       if(paramInt01>0){
-        /*var checkeds = quItemBody.find("input[type='checkbox']:checked");
+        var checkeds = quItemBody.find("input[type='checkbox']:checked");
         if(checkeds[0]&&checkeds.size()<paramInt01){
           quItemBody.find(".quCoItem").append("<div class=\"errorItem\"><label class=\"error\">请保证最少选择"+paramInt01+"项内容</label></div>");
           validateStatus = false;
         }else{
           quItemBody.find(".quCoItem .errorItem").remove();
-        }*/
+        }
       }
       if(validateStatus){
 //					isNote checkType isRequiredFill
@@ -1029,6 +1030,8 @@ function validateCheck(quItemBody,isSubForm){
           }
         }
       }
+    }else if(quType === "UPLOADFILE"){
+      validateStatus=quItemBody.find(".fileuploadSaveValue")[0];
     }else if(quType==="submitSurveyBtn" || quType==="PARAGRAPH" || quType==="PAGETAG"){
       return true;
     }

+ 18 - 0
src/main/resources/static/static/diaowen/js/dw/design-data.js

@@ -34,6 +34,8 @@ function querySurveyAll(){
                parsePage(item);
              }else if(quType==="PARAGRAPH"){
                parseParagraph(item);
+             }else if(quType == "UPLOADFILE"){
+               parseUploadfile(item);
              }
            });
            resetQuItem();
@@ -387,3 +389,19 @@ function parseParagraph(item){
 
 }
 
+function parseUploadfile(item){
+  var quModel = $("#uploadFileQuModel .dwQuTypeModel").html();
+  $("#dwSurveyQuContentAppUl").append("<li class=\"li_surveyQuItemBody\">"+quModel+"</li>");
+  var lastQuItemBody = $("#dwSurveyQuContentAppUl .li_surveyQuItemBody").last()
+  lastQuItemBody.find(".quDragBody").removeClass("quDragBody");
+  var quInputCase = lastQuItemBody.find(".quInputCase");
+  parseExtracted(quInputCase, item);
+  quInputCase.find("input[name='contactsAttr']").val(item.contactsAttr);
+  quInputCase.find("input[name='contactsField']").val(item.contactsField);
+  quInputCase.find("input[name='checkType']").val(item.checkType);
+  quInputCase.find("input[name='answerInputWidth']").val(item.answerInputWidth);
+  quInputCase.find("input[name='answerInputRow']").val(item.answerInputRow);
+  quInputCase.find("input[name='paramStr01']").val(item.paramStr01);
+  quLogicExtracted(lastQuItemBody, item);
+
+}

+ 143 - 3
src/main/resources/static/static/diaowen/js/dw/dwsurvey-design.js

@@ -437,6 +437,12 @@ $(document).ready(function(){
 			if(quType=="RADIO" || quType=="CHECKBOX" || quType=="FILLBLANK"){
 				quItemBody.find("input[name='contactsAttr']").val(setAutoContacts[0]?1:0);
 				quItemBody.find("input[name='contactsField']").val(setContactsField);
+        if(quType=="CHECKBOX"){
+          var minNum = $("#dwCommonDialog .minNumLi input[name='minNum']").val();
+          var maxNum = $("#dwCommonDialog .maxNumLi input[name='maxNum']").val();
+          quItemBody.find("input[name='paramInt01']").val(minNum);
+          quItemBody.find("input[name='paramInt02']").val(maxNum);
+        }
 			}else if(quType==="MULTIFILLBLANK"){
 				var paramInt01=$("#dwCommonDialog .minMaxLi .minNum");
 				if(paramInt01[0]){
@@ -459,7 +465,14 @@ $(document).ready(function(){
 						$(this).append("<td>"+i+"</td>");
 					}
 				});
-			}
+			}else if(quType==="UPLOADFILE"){
+        var fileTypeExtsField=$("#dwCommonDialog .fileTypeExts");
+        var maxSizeField=$("#dwCommonDialog .maxSize");
+        var uploadNumField=$("#dwCommonDialog .uploadNum");
+        quItemBody.find("input[name='paramInt01']").val(fileTypeExtsField.val());
+        quItemBody.find("input[name='paramInt02']").val(maxSizeField.val());
+        quItemBody.find("input[name='randOrder']").val(uploadNumField.val());
+      }
 
 			var selVal=$(".option_range").val();
 			if(selVal==1){
@@ -1473,6 +1486,8 @@ function showDialog(thDialogObj){
 		$("#dwCommonDialog .optionRangeHv").hide();
 		$("#dwCommonDialog .scoreMinMax").hide();
 		$("#dwCommonDialog .minMaxLi").hide();
+    $("#dwCommonDialog .minNumLi").hide();
+    $("#dwCommonDialog .maxNumLi").hide();
 		if(isRequired==1){
 			$("#dwCommonDialog input[name='setIsRequired']").prop("checked",true);
 		}
@@ -1507,6 +1522,7 @@ function showDialog(thDialogObj){
 			}
 		}
 
+    $("#dwCommonDialog .fileTypeExtsLi").hide();
 		//单选,多选,填空题情况下才启用关联到联系设置项
 		if((quType=="RADIO" || quType=="CHECKBOX" || quType=="FILLBLANK")){
 			if( contactsAttr==1){
@@ -1514,7 +1530,22 @@ function showDialog(thDialogObj){
 				$("#dwCommonDialog .contactsFieldLi").show();
 				$("#dwCommonDialog select[name='setContactsField']").val(contactsField);
 			}
-		}
+      if(quType == "CHECKBOX"){
+        $("#dwCommonDialog .minNumLi").show();
+        $("#dwCommonDialog .maxNumLi").show();
+        $("#dwCommonDialog .minNumLi input[name='minNum']").val(paramInt01.val());
+        $("#dwCommonDialog .maxNumLi input[name='maxNum']").val(paramInt02.val());
+      }
+    } else if(quType==="UPLOADFILE"){
+      // fileTypeExtsLi
+      if(paramInt01[0]){
+        $("#dwCommonDialog .fileTypeExts").val(paramInt01.val());
+        $("#dwCommonDialog .maxSize").val(paramInt02.val());
+        $("#dwCommonDialog .uploadNum").val(randOrder);
+      }
+      $("#dwCommonDialog .fileTypeExtsLi").show();
+      $("#dwCommonDialog .minMaxNumLi").hide();
+    }
 	}else if(thObjClass.indexOf("dwQuLogic")>=0){
 		$("#dwCommonDialog .dwQuDialogLoad").show();
 	}else if(thObjClass.indexOf("dwFbMenuBtn")>=0){
@@ -1677,7 +1708,9 @@ function saveQus(quItemBody,callback){
 				saveMultiFillblank(quItemBody, callback);
 			}else if(quType=="SCORE"){
 				saveScore(quItemBody, callback);
-			}else{
+			}else if(quType == "UPLOADFILE"){
+        saveUploadFile(quItemBody, callback);
+      }else{
 				callback();
 			}
 		}else{
@@ -1907,10 +1940,13 @@ function saveCheckbox(quItemBody,callback){
 		var cellCount=quItemBody.find("input[name='cellCount']").val();
 		var contactsAttr=quItemBody.find("input[name='contactsAttr']").val();
 		var contactsField=quItemBody.find("input[name='contactsField']").val();
+    var paramInt01=quItemBody.find("input[name='paramInt01']").val();
+    var paramInt02=quItemBody.find("input[name='paramInt02']").val();
 
 		var data="belongId="+questionBelongId+"&orderById="+orderById+"&tag="+svTag+"&quType="+quType+"&quId="+quId;
 		data+="&isRequired="+isRequired+"&hv="+hv+"&randOrder="+randOrder+"&cellCount="+cellCount;
 		data+="&contactsAttr="+contactsAttr+"&contactsField="+contactsField;
+    data+="&paramInt01="+paramInt01+"&paramInt02="+paramInt02;
 
 		var quTitleSaveTag=quItemBody.find("input[name='quTitleSaveTag']").val();
 		if(quTitleSaveTag==0){
@@ -2904,6 +2940,110 @@ function deleteMultiFillblankOption(){
 	}
 }
 
+/**
+ * 文件上传题
+ * @param quItemBody
+ * @param callback
+ */
+function saveUploadFile(quItemBody,callback){
+  var saveTag=quItemBody.find("input[name='saveTag']").val();
+  if(saveTag==0){
+    var url=ctx+"/design/qu-upload-file/ajaxSave.do";
+    var quType=quItemBody.find("input[name='quType']").val();
+    var quId=quItemBody.find("input[name='quId']").val();
+    var orderById=quItemBody.find("input[name='orderById']").val();;
+    var isRequired=quItemBody.find("input[name='isRequired']").val();
+    var hv=quItemBody.find("input[name='hv']").val();
+    var randOrder=quItemBody.find("input[name='randOrder']").val();
+    var cellCount=quItemBody.find("input[name='cellCount']").val();
+
+    var answerInputWidth=quItemBody.find("input[name='answerInputWidth']").val();
+    var answerInputRow=quItemBody.find("input[name='answerInputRow']").val();
+
+    var contactsAttr=quItemBody.find("input[name='contactsAttr']").val();
+    var contactsField=quItemBody.find("input[name='contactsField']").val();
+
+    var checkType=quItemBody.find("input[name='checkType']").val();
+    var paramInt01=quItemBody.find("input[name='paramInt01']").val();
+    var paramInt02=quItemBody.find("input[name='paramInt02']").val();
+
+    var data="belongId="+questionBelongId+"&orderById="+orderById+"&tag="+svTag+"&quType="+quType+"&quId="+quId;
+    data+="&isRequired="+isRequired+"&hv="+hv+"&randOrder="+randOrder+"&cellCount="+cellCount;
+    data+="&answerInputWidth="+answerInputWidth+"&answerInputRow="+answerInputRow;
+    data+="&contactsAttr="+contactsAttr+"&contactsField="+contactsField+"&checkType="+checkType;
+    data+="&paramInt01="+paramInt01;
+    data+="&paramInt02="+paramInt02;
+
+    var quTitleSaveTag=quItemBody.find("input[name='quTitleSaveTag']").val();
+    if(quTitleSaveTag==0){
+      var quTitle=quItemBody.find(".quCoTitleEdit").html();
+      quTitle=escape(encodeURIComponent(quTitle));
+      data+="&quTitle="+quTitle;
+    }
+
+    //逻辑选项
+    var quLogicItems=quItemBody.find(".quLogicItem");
+    $.each(quLogicItems,function(i){
+      var thClass=$(this).attr("class");
+      thClass=thClass.replace("quLogicItem quLogicItem_","");
+
+      var quLogicId=$(this).find("input[name='quLogicId']").val();
+      var cgQuItemId=$(this).find("input[name='cgQuItemId']").val();
+      var skQuId=$(this).find("input[name='skQuId']").val();
+      var logicSaveTag=$(this).find("input[name='logicSaveTag']").val();
+      var visibility=$(this).find("input[name='visibility']").val();
+      var logicType=$(this).find("input[name='logicType']").val();
+      var itemIndex=thClass;
+      if(logicSaveTag==0){
+        data+="&quLogicId_"+itemIndex+"="+quLogicId;
+        data+="&cgQuItemId_"+itemIndex+"="+cgQuItemId;
+        data+="&skQuId_"+itemIndex+"="+skQuId;
+        data+="&visibility_"+itemIndex+"="+visibility;
+        data+="&logicType_"+itemIndex+"="+logicType;
+      }
+
+    });
+
+    // alert(data);
+    $.ajax({
+      url:url,
+      data:data,
+      type:'post',
+      success:function(msg){
+        //alert(msg);// resultJson quItemId
+        if(msg!="error"){
+          var jsons=eval("("+msg+")");
+          //alert(jsons);
+          var quId=jsons.id;
+          quItemBody.find("input[name='quId']").val(quId);
+
+          //同步logic Id信息
+          var quLogics=jsons.quLogics;
+          $.each(quLogics,function(i,item){
+            var logicItem=quItemBody.find(".quLogicItem_"+item.title);
+            logicItem.find("input[name='quLogicId']").val(item.id);
+            logicItem.find("input[name='logicSaveTag']").val(1);
+          });
+
+          quItemBody.find("input[name='saveTag']").val(1);
+          quItemBody.find(".quCoTitle input[name='quTitleSaveTag']").val(1);
+
+          quItemBody.removeClass("saveError");
+        }else{
+          quItemBody.addClass("saveError");
+        }
+        //执行保存下一题
+        saveQus(quItemBody.next(),callback);
+        //同步-更新题目排序号
+        quCBNum2++;
+        exeQuCBNum();
+      }
+    });
+  }else{
+    saveQus(quItemBody.next(),callback);
+  }
+}
+
 
 /**逻辑设置**/
 //添加逻辑选项

+ 15 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/CONTRIBUTING.md

@@ -0,0 +1,15 @@
+Please follow these pull request guidelines:
+
+1. Update your fork to the latest upstream version.
+
+2. Follow the coding conventions of the original source files (indentation, spaces, brackets layout).
+
+3. Code changes must pass JSHint validation with the `.jshintrc` settings of this project.
+
+4. Code changes must pass the QUnit tests defined in the `test` folder.
+
+5. New features should be covered by accompanying QUnit tests.
+
+6. Keep your commits as atomic as possible, i.e. create a new commit for every single bug fix or feature added.
+
+7. Always add meaningful commit messages.

+ 21 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/LICENSE.txt

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright © 2010 Sebastian Tschan, https://blueimp.net
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 107 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/README.md

@@ -0,0 +1,107 @@
+# jQuery File Upload Plugin
+
+## Demo
+[Demo File Upload](https://blueimp.github.io/jQuery-File-Upload/)
+
+## Description
+File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery.  
+Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
+
+## Setup
+* [How to setup the plugin on your website](https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
+* [How to use only the basic plugin (minimal setup guide).](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin)
+
+## Features
+* **Multiple file upload:**  
+  Allows to select multiple files at once and upload them simultaneously.
+* **Drag & Drop support:**  
+  Allows to upload files by dragging them from your desktop or filemanager and dropping them on your browser window.
+* **Upload progress bar:**  
+  Shows a progress bar indicating the upload progress for individual files and for all uploads combined.
+* **Cancelable uploads:**  
+  Individual file uploads can be canceled to stop the upload progress.
+* **Resumable uploads:**  
+  Aborted uploads can be resumed with browsers supporting the Blob API.
+* **Chunked uploads:**  
+  Large files can be uploaded in smaller chunks with browsers supporting the Blob API.
+* **Client-side image resizing:**  
+  Images can be automatically resized on client-side with browsers supporting the required JS APIs.
+* **Preview images, audio and video:**  
+  A preview of image, audio and video files can be displayed before uploading with browsers supporting the required APIs.
+* **No browser plugins (e.g. Adobe Flash) required:**  
+  The implementation is based on open standards like HTML5 and JavaScript and requires no additional browser plugins.
+* **Graceful fallback for legacy browsers:**  
+  Uploads files via XMLHttpRequests if supported and uses iframes as fallback for legacy browsers.
+* **HTML file upload form fallback:**  
+  Allows progressive enhancement by using a standard HTML file upload form as widget element.
+* **Cross-site file uploads:**  
+  Supports uploading files to a different domain with cross-site XMLHttpRequests or iframe redirects.
+* **Multiple plugin instances:**  
+  Allows to use multiple plugin instances on the same webpage.
+* **Customizable and extensible:**  
+  Provides an API to set individual options and define callback methods for various upload events.
+* **Multipart and file contents stream uploads:**  
+  Files can be uploaded as standard "multipart/form-data" or file contents stream (HTTP PUT file upload).
+* **Compatible with any server-side application platform:**  
+  Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
+
+## Requirements
+
+### Mandatory requirements
+* [jQuery](https://jquery.com/) v. 1.6+
+* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included): Required for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite.
+* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included): Required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
+
+### Optional requirements
+* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+: Used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions.
+* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+: Required for the image previews and resizing functionality.
+* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+:Required for the image previews and resizing functionality.
+* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+: Used to display the uploaded images in a lightbox.
+* [Bootstrap](http://getbootstrap.com/) v. 3.2.0+
+* [Glyphicons](http://glyphicons.com/)
+
+The user interface of all versions, except the jQuery UI version, is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/).
+
+### Cross-domain requirements
+[Cross-domain File Uploads](https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads) using the [Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) require a redirect back to the origin server to retrieve the upload results. The [example implementation](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/main.js) makes use of [result.html](https://github.com/blueimp/jQuery-File-Upload/blob/master/cors/result.html) as a static redirect page for the origin server.
+
+The repository also includes the [jQuery XDomainRequest Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/cors/jquery.xdr-transport.js), which enables limited cross-domain AJAX requests in Microsoft Internet Explorer 8 and 9 (IE 10 supports cross-domain XHR requests).  
+The XDomainRequest object allows GET and POST requests only and doesn't support file uploads. It is used on the [Demo](https://blueimp.github.io/jQuery-File-Upload/) to delete uploaded files from the cross-domain demo file upload service.
+
+### Custom Backends
+
+You can add support for various backends by adhering to the specification [outlined here](https://github.com/blueimp/jQuery-File-Upload/wiki/JSON-Response).
+
+## Browsers
+
+### Desktop browsers
+The File Upload plugin is regularly tested with the latest browser versions and supports the following minimal versions:
+
+* Google Chrome
+* Apple Safari 4.0+
+* Mozilla Firefox 3.0+
+* Opera 11.0+
+* Microsoft Internet Explorer 6.0+
+
+### Mobile browsers
+The File Upload plugin has been tested with and supports the following mobile browsers:
+
+* Apple Safari on iOS 6.0+
+* Google Chrome on iOS 6.0+
+* Google Chrome on Android 4.0+
+* Default Browser on Android 2.3+
+* Opera Mobile 12.0+
+
+### Supported features
+For a detailed overview of the features supported by each browser version, please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
+
+## Contributing
+**Bug fixes** and **new features** can be proposed using [pull requests](https://github.com/blueimp/jQuery-File-Upload/pulls).
+Please read the [contribution guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before submitting a pull request.
+
+## Support
+This project is actively maintained, but there is no official support channel.  
+If you have a question that another developer might help you with, please post to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload) and tag your question with `blueimp jquery file upload`.
+
+## License
+Released under the [MIT license](https://opensource.org/licenses/MIT).

+ 211 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/angularjs.html

@@ -0,0 +1,211 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery File Upload Plugin AngularJS Demo
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<!-- Force latest IE rendering engine or ChromeFrame if installed -->
+<!--[if IE]>
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<![endif]-->
+<meta charset="utf-8">
+<title>jQuery File Upload Demo - AngularJS version</title>
+<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for AngularJS. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<!-- Bootstrap styles -->
+<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<!-- Generic page styles -->
+<link rel="stylesheet" href="css/style.css">
+<!-- blueimp Gallery styles -->
+<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
+<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
+<link rel="stylesheet" href="css/jquery.fileupload.css">
+<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
+<!-- CSS adjustments for browsers with JavaScript disabled -->
+<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
+<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
+<style>
+/* Hide Angular JS elements before initializing */
+.ng-cloak {
+    display: none;
+}
+</style>
+</head>
+<body>
+<div class="navbar navbar-default navbar-fixed-top">
+    <div class="container">
+        <div class="navbar-header">
+            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
+        </div>
+        <div class="navbar-collapse collapse">
+            <ul class="nav navbar-nav">
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
+                <li><a href="https://blueimp.net">&copy; Sebastian Tschan</a></li>
+            </ul>
+        </div>
+    </div>
+</div>
+<div class="container">
+    <h1>jQuery File Upload Demo</h1>
+    <h2 class="lead">AngularJS version</h2>
+    <ul class="nav nav-tabs">
+        <li><a href="basic.html">Basic</a></li>
+        <li><a href="basic-plus.html">Basic Plus</a></li>
+        <li><a href="index.html">Basic Plus UI</a></li>
+        <li class="active"><a href="angularjs.html">AngularJS</a></li>
+        <li><a href="jquery-ui.html">jQuery UI</a></li>
+    </ul>
+    <br>
+    <blockquote>
+        <p>File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for AngularJS.<br>
+        Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
+        Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
+    </blockquote>
+    <br>
+    <!-- The file upload form used as target for the file upload widget -->
+    <form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data" data-ng-app="demo" data-ng-controller="DemoFileUploadController" data-file-upload="options" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
+        <!-- Redirect browsers with JavaScript disabled to the origin page -->
+        <noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
+        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
+        <div class="row fileupload-buttonbar">
+            <div class="col-lg-7">
+                <!-- The fileinput-button span is used to style the file input field as button -->
+                <span class="btn btn-success fileinput-button" ng-class="{disabled: disabled}">
+                    <i class="glyphicon glyphicon-plus"></i>
+                    <span>Add files...</span>
+                    <input type="file" name="files[]" multiple ng-disabled="disabled">
+                </span>
+                <button type="button" class="btn btn-primary start" data-ng-click="submit()">
+                    <i class="glyphicon glyphicon-upload"></i>
+                    <span>Start upload</span>
+                </button>
+                <button type="button" class="btn btn-warning cancel" data-ng-click="cancel()">
+                    <i class="glyphicon glyphicon-ban-circle"></i>
+                    <span>Cancel upload</span>
+                </button>
+                <!-- The global file processing state -->
+                <span class="fileupload-process"></span>
+            </div>
+            <!-- The global progress state -->
+            <div class="col-lg-5 fade" data-ng-class="{in: active()}">
+                <!-- The global progress bar -->
+                <div class="progress progress-striped active" data-file-upload-progress="progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
+                <!-- The extended global progress state -->
+                <div class="progress-extended">&nbsp;</div>
+            </div>
+        </div>
+        <!-- The table listing the files available for upload/download -->
+        <table class="table table-striped files ng-cloak">
+            <tr data-ng-repeat="file in queue" data-ng-class="{'processing': file.$processing()}">
+                <td data-ng-switch data-on="!!file.thumbnailUrl">
+                    <div class="preview" data-ng-switch-when="true">
+                        <a data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery><img data-ng-src="{{file.thumbnailUrl}}" alt=""></a>
+                    </div>
+                    <div class="preview" data-ng-switch-default data-file-upload-preview="file"></div>
+                </td>
+                <td>
+                    <p class="name" data-ng-switch data-on="!!file.url">
+                        <span data-ng-switch-when="true" data-ng-switch data-on="!!file.thumbnailUrl">
+                            <a data-ng-switch-when="true" data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery>{{file.name}}</a>
+                            <a data-ng-switch-default data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}">{{file.name}}</a>
+                        </span>
+                        <span data-ng-switch-default>{{file.name}}</span>
+                    </p>
+                    <strong data-ng-show="file.error" class="error text-danger">{{file.error}}</strong>
+                </td>
+                <td>
+                    <p class="size">{{file.size | formatFileSize}}</p>
+                    <div class="progress progress-striped active fade" data-ng-class="{pending: 'in'}[file.$state()]" data-file-upload-progress="file.$progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
+                </td>
+                <td>
+                    <button type="button" class="btn btn-primary start" data-ng-click="file.$submit()" data-ng-hide="!file.$submit || options.autoUpload" data-ng-disabled="file.$state() == 'pending' || file.$state() == 'rejected'">
+                        <i class="glyphicon glyphicon-upload"></i>
+                        <span>Start</span>
+                    </button>
+                    <button type="button" class="btn btn-warning cancel" data-ng-click="file.$cancel()" data-ng-hide="!file.$cancel">
+                        <i class="glyphicon glyphicon-ban-circle"></i>
+                        <span>Cancel</span>
+                    </button>
+                    <button data-ng-controller="FileDestroyController" type="button" class="btn btn-danger destroy" data-ng-click="file.$destroy()" data-ng-hide="!file.$destroy">
+                        <i class="glyphicon glyphicon-trash"></i>
+                        <span>Delete</span>
+                    </button>
+                </td>
+            </tr>
+        </table>
+    </form>
+    <br>
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h3 class="panel-title">Demo Notes</h3>
+        </div>
+        <div class="panel-body">
+            <ul>
+                <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
+                <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
+                <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
+                <li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
+                <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
+                <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
+            </ul>
+        </div>
+    </div>
+</div>
+<!-- The blueimp Gallery widget -->
+<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
+    <div class="slides"></div>
+    <h3 class="title"></h3>
+    <a class="prev">‹</a>
+    <a class="next">›</a>
+    <a class="close">×</a>
+    <a class="play-pause"></a>
+    <ol class="indicator"></ol>
+</div>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
+<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
+<script src="js/vendor/jquery.ui.widget.js"></script>
+<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<!-- The Canvas to Blob plugin is included for image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
+<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<!-- blueimp Gallery script -->
+<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
+<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
+<script src="js/jquery.iframe-transport.js"></script>
+<!-- The basic File Upload plugin -->
+<script src="js/jquery.fileupload.js"></script>
+<!-- The File Upload processing plugin -->
+<script src="js/jquery.fileupload-process.js"></script>
+<!-- The File Upload image preview & resize plugin -->
+<script src="js/jquery.fileupload-image.js"></script>
+<!-- The File Upload audio preview plugin -->
+<script src="js/jquery.fileupload-audio.js"></script>
+<!-- The File Upload video preview plugin -->
+<script src="js/jquery.fileupload-video.js"></script>
+<!-- The File Upload validation plugin -->
+<script src="js/jquery.fileupload-validate.js"></script>
+<!-- The File Upload Angular JS module -->
+<script src="js/jquery.fileupload-angular.js"></script>
+<!-- The main application script -->
+<script src="js/app.js"></script>
+</body>
+</html>

+ 226 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/basic-plus.html

@@ -0,0 +1,226 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery File Upload Plugin Basic Plus Demo
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<!-- Force latest IE rendering engine or ChromeFrame if installed -->
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><![endif]-->
+<meta charset="utf-8">
+<title>jQuery File Upload Demo - Basic Plus version</title>
+<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<!-- Bootstrap styles -->
+<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<!-- Generic page styles -->
+<link rel="stylesheet" href="css/style.css">
+<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
+<link rel="stylesheet" href="css/jquery.fileupload.css">
+</head>
+<body>
+<div class="navbar navbar-default navbar-fixed-top">
+    <div class="container">
+        <div class="navbar-header">
+            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
+        </div>
+        <div class="navbar-collapse collapse">
+            <ul class="nav navbar-nav">
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
+                <li><a href="https://blueimp.net">&copy; Sebastian Tschan</a></li>
+            </ul>
+        </div>
+    </div>
+</div>
+<div class="container">
+    <h1>jQuery File Upload Demo</h1>
+    <h2 class="lead">Basic Plus version</h2>
+    <ul class="nav nav-tabs">
+        <li><a href="basic.html">Basic</a></li>
+        <li class="active"><a href="basic-plus.html">Basic Plus</a></li>
+        <li><a href="index.html">Basic Plus UI</a></li>
+        <li><a href="angularjs.html">AngularJS</a></li>
+        <li><a href="jquery-ui.html">jQuery UI</a></li>
+    </ul>
+    <br>
+    <blockquote>
+        <p>File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images, audio and video for jQuery.<br>
+        Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
+        Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
+    </blockquote>
+    <br>
+    <!-- The fileinput-button span is used to style the file input field as button -->
+    <span class="btn btn-success fileinput-button">
+        <i class="glyphicon glyphicon-plus"></i>
+        <span>Add files...</span>
+        <!-- The file input field used as target for the file upload widget -->
+        <input id="fileupload" type="file" name="files[]" multiple>
+    </span>
+    <br>
+    <br>
+    <!-- The global progress bar -->
+    <div id="progress" class="progress">
+        <div class="progress-bar progress-bar-success"></div>
+    </div>
+    <!-- The container for the uploaded files -->
+    <div id="files" class="files"></div>
+    <br>
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h3 class="panel-title">Demo Notes</h3>
+        </div>
+        <div class="panel-body">
+            <ul>
+                <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
+                <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
+                <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
+                <li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
+                <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
+                <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
+            </ul>
+        </div>
+    </div>
+</div>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
+<script src="js/vendor/jquery.ui.widget.js"></script>
+<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<!-- The Canvas to Blob plugin is included for image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
+<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
+<script src="js/jquery.iframe-transport.js"></script>
+<!-- The basic File Upload plugin -->
+<script src="js/jquery.fileupload.js"></script>
+<!-- The File Upload processing plugin -->
+<script src="js/jquery.fileupload-process.js"></script>
+<!-- The File Upload image preview & resize plugin -->
+<script src="js/jquery.fileupload-image.js"></script>
+<!-- The File Upload audio preview plugin -->
+<script src="js/jquery.fileupload-audio.js"></script>
+<!-- The File Upload video preview plugin -->
+<script src="js/jquery.fileupload-video.js"></script>
+<!-- The File Upload validation plugin -->
+<script src="js/jquery.fileupload-validate.js"></script>
+<script>
+/*jslint unparam: true, regexp: true */
+/*global window, $ */
+$(function () {
+    'use strict';
+    // Change this to the location of your server-side upload handler:
+    var url = window.location.hostname === 'blueimp.github.io' ?
+                '//jquery-file-upload.appspot.com/' : 'server/php/',
+        uploadButton = $('<button/>')
+            .addClass('btn btn-primary')
+            .prop('disabled', true)
+            .text('Processing...')
+            .on('click', function () {
+                var $this = $(this),
+                    data = $this.data();
+                $this
+                    .off('click')
+                    .text('Abort')
+                    .on('click', function () {
+                        $this.remove();
+                        data.abort();
+                    });
+                data.submit().always(function () {
+                    $this.remove();
+                });
+            });
+    $('#fileupload').fileupload({
+        url: url,
+        dataType: 'json',
+        autoUpload: false,
+        acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
+        maxFileSize: 999000,
+        // Enable image resizing, except for Android and Opera,
+        // which actually support image resizing, but fail to
+        // send Blob objects via XHR requests:
+        disableImageResize: /Android(?!.*Chrome)|Opera/
+            .test(window.navigator.userAgent),
+        previewMaxWidth: 100,
+        previewMaxHeight: 100,
+        previewCrop: true
+    }).on('fileuploadadd', function (e, data) {
+        data.context = $('<div/>').appendTo('#files');
+        $.each(data.files, function (index, file) {
+            var node = $('<p/>')
+                    .append($('<span/>').text(file.name));
+            if (!index) {
+                node
+                    .append('<br>')
+                    .append(uploadButton.clone(true).data(data));
+            }
+            node.appendTo(data.context);
+        });
+    }).on('fileuploadprocessalways', function (e, data) {
+        var index = data.index,
+            file = data.files[index],
+            node = $(data.context.children()[index]);
+        if (file.preview) {
+            node
+                .prepend('<br>')
+                .prepend(file.preview);
+        }
+        if (file.error) {
+            node
+                .append('<br>')
+                .append($('<span class="text-danger"/>').text(file.error));
+        }
+        if (index + 1 === data.files.length) {
+            data.context.find('button')
+                .text('Upload')
+                .prop('disabled', !!data.files.error);
+        }
+    }).on('fileuploadprogressall', function (e, data) {
+        var progress = parseInt(data.loaded / data.total * 100, 10);
+        $('#progress .progress-bar').css(
+            'width',
+            progress + '%'
+        );
+    }).on('fileuploaddone', function (e, data) {
+        $.each(data.result.files, function (index, file) {
+            if (file.url) {
+                var link = $('<a>')
+                    .attr('target', '_blank')
+                    .prop('href', file.url);
+                $(data.context.children()[index])
+                    .wrap(link);
+            } else if (file.error) {
+                var error = $('<span class="text-danger"/>').text(file.error);
+                $(data.context.children()[index])
+                    .append('<br>')
+                    .append(error);
+            }
+        });
+    }).on('fileuploadfail', function (e, data) {
+        $.each(data.files, function (index) {
+            var error = $('<span class="text-danger"/>').text('File upload failed.');
+            $(data.context.children()[index])
+                .append('<br>')
+                .append(error);
+        });
+    }).prop('disabled', !$.support.fileInput)
+        .parent().addClass($.support.fileInput ? undefined : 'disabled');
+});
+</script>
+</body>
+</html>

+ 136 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/basic.html

@@ -0,0 +1,136 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery File Upload Plugin Basic Demo
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<!-- Force latest IE rendering engine or ChromeFrame if installed -->
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><![endif]-->
+<meta charset="utf-8">
+<title>jQuery File Upload Demo - Basic version</title>
+<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support and progress bar for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<!-- Bootstrap styles -->
+<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<!-- Generic page styles -->
+<link rel="stylesheet" href="css/style.css">
+<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
+<link rel="stylesheet" href="css/jquery.fileupload.css">
+</head>
+<body>
+<div class="navbar navbar-default navbar-fixed-top">
+    <div class="container">
+        <div class="navbar-header">
+            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
+        </div>
+        <div class="navbar-collapse collapse">
+            <ul class="nav navbar-nav">
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
+                <li><a href="https://blueimp.net">&copy; Sebastian Tschan</a></li>
+            </ul>
+        </div>
+    </div>
+</div>
+<div class="container">
+    <h1>jQuery File Upload Demo</h1>
+    <h2 class="lead">Basic version</h2>
+    <ul class="nav nav-tabs">
+        <li class="active"><a href="basic.html">Basic</a></li>
+        <li><a href="basic-plus.html">Basic Plus</a></li>
+        <li><a href="index.html">Basic Plus UI</a></li>
+        <li><a href="angularjs.html">AngularJS</a></li>
+        <li><a href="jquery-ui.html">jQuery UI</a></li>
+    </ul>
+    <br>
+    <blockquote>
+        <p>File Upload widget with multiple file selection, drag&amp;drop support and progress bar for jQuery.<br>
+        Supports cross-domain, chunked and resumable file uploads.<br>
+        Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
+    </blockquote>
+    <br>
+    <!-- The fileinput-button span is used to style the file input field as button -->
+    <span class="btn btn-success fileinput-button">
+        <i class="glyphicon glyphicon-plus"></i>
+        <span>Select files...</span>
+        <!-- The file input field used as target for the file upload widget -->
+        <input id="fileupload" type="file" name="files[]" multiple>
+    </span>
+    <br>
+    <br>
+    <!-- The global progress bar -->
+    <div id="progress" class="progress">
+        <div class="progress-bar progress-bar-success"></div>
+    </div>
+    <!-- The container for the uploaded files -->
+    <div id="files" class="files"></div>
+    <br>
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h3 class="panel-title">Demo Notes</h3>
+        </div>
+        <div class="panel-body">
+            <ul>
+                <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
+                <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
+                <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
+                <li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
+                <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
+                <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
+            </ul>
+        </div>
+    </div>
+</div>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
+<script src="js/vendor/jquery.ui.widget.js"></script>
+<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
+<script src="js/jquery.iframe-transport.js"></script>
+<!-- The basic File Upload plugin -->
+<script src="js/jquery.fileupload.js"></script>
+<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
+<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<script>
+/*jslint unparam: true */
+/*global window, $ */
+$(function () {
+    'use strict';
+    // Change this to the location of your server-side upload handler:
+    var url = window.location.hostname === 'blueimp.github.io' ?
+                '//jquery-file-upload.appspot.com/' : 'server/php/';
+    $('#fileupload').fileupload({
+        url: url,
+        dataType: 'json',
+        done: function (e, data) {
+            $.each(data.result.files, function (index, file) {
+                $('<p/>').text(file.name).appendTo('#files');
+            });
+        },
+        progressall: function (e, data) {
+            var progress = parseInt(data.loaded / data.total * 100, 10);
+            $('#progress .progress-bar').css(
+                'width',
+                progress + '%'
+            );
+        }
+    }).prop('disabled', !$.support.fileInput)
+        .parent().addClass($.support.fileInput ? undefined : 'disabled');
+});
+</script>
+</body>
+</html>

+ 16 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/bower-version-update.js

@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+
+'use strict';
+
+var path = require('path');
+var packageJSON = require(path.join(__dirname, 'package.json'));
+var bowerFile = path.join(__dirname, 'bower.json');
+var bowerJSON = require('bower-json').parse(
+  require(bowerFile),
+  {normalize: true}
+);
+bowerJSON.version = packageJSON.version;
+require('fs').writeFileSync(
+  bowerFile,
+  JSON.stringify(bowerJSON, null, 2) + '\n'
+);

+ 64 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/bower.json

@@ -0,0 +1,64 @@
+{
+  "name": "blueimp-file-upload",
+  "version": "9.19.2",
+  "title": "jQuery File Upload",
+  "description": "File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images.",
+  "keywords": [
+    "jquery",
+    "file",
+    "upload",
+    "widget",
+    "multiple",
+    "selection",
+    "drag",
+    "drop",
+    "progress",
+    "preview",
+    "cross-domain",
+    "cross-site",
+    "chunk",
+    "resume",
+    "gae",
+    "go",
+    "python",
+    "php",
+    "bootstrap"
+  ],
+  "homepage": "https://github.com/blueimp/jQuery-File-Upload",
+  "author": {
+    "name": "Sebastian Tschan",
+    "url": "https://blueimp.net"
+  },
+  "maintainers": [
+    {
+      "name": "Sebastian Tschan",
+      "url": "https://blueimp.net"
+    }
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/blueimp/jQuery-File-Upload.git"
+  },
+  "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues",
+  "license": "MIT",
+  "dependencies": {
+    "jquery": ">=1.6",
+    "blueimp-tmpl": ">=2.5.4",
+    "blueimp-load-image": ">=1.13.0",
+    "blueimp-canvas-to-blob": ">=2.1.1"
+  },
+  "main": [
+    "js/jquery.fileupload.js"
+  ],
+  "ignore": [
+    "/*.*",
+    "/cors",
+    "css/jquery-ui-demo-ie8.css",
+    "css/jquery-ui-demo.css",
+    "css/style.css",
+    "js/app.js",
+    "js/main.js",
+    "server",
+    "test"
+  ]
+}

+ 75 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/cors/postmessage.html

@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery File Upload Plugin postMessage API
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<title>jQuery File Upload Plugin postMessage API</title>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
+</head>
+<body>
+<script>
+/*jslint unparam: true, regexp: true */
+/*global $, Blob, FormData, location */
+'use strict';
+var origin = /^http:\/\/example.org/,
+    target = new RegExp('^(http(s)?:)?\\/\\/' + location.host + '\\/');
+$(window).on('message', function (e) {
+    e = e.originalEvent;
+    var s = e.data,
+        xhr = $.ajaxSettings.xhr(),
+        f;
+    if (!origin.test(e.origin)) {
+        throw new Error('Origin "' + e.origin + '" does not match ' + origin);
+    }
+    if (!target.test(e.data.url)) {
+        throw new Error('Target "' + e.data.url + '" does not match ' + target);
+    }
+    $(xhr.upload).on('progress', function (ev) {
+        ev = ev.originalEvent;
+        e.source.postMessage({
+            id: s.id,
+            type: ev.type,
+            timeStamp: ev.timeStamp,
+            lengthComputable: ev.lengthComputable,
+            loaded: ev.loaded,
+            total: ev.total
+        }, e.origin);
+    });
+    s.xhr = function () {
+        return xhr;
+    };
+    if (!(s.data instanceof Blob)) {
+        f = new FormData();
+        $.each(s.data, function (i, v) {
+            f.append(v.name, v.value);
+        });
+        s.data = f;
+    }
+    $.ajax(s).always(function (result, statusText, jqXHR) {
+        if (!jqXHR.done) {
+            jqXHR = result;
+            result = null;
+        }
+        e.source.postMessage({
+            id: s.id,
+            status: jqXHR.status,
+            statusText: statusText,
+            result: result,
+            headers: jqXHR.getAllResponseHeaders()
+        }, e.origin);
+    });
+});
+</script>
+</body>
+</html>

+ 24 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/cors/result.html

@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery Iframe Transport Plugin Redirect Page
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<title>jQuery Iframe Transport Plugin Redirect Page</title>
+</head>
+<body>
+<script>
+document.body.innerText=document.body.textContent=decodeURIComponent(window.location.search.slice(1));
+</script>
+</body>
+</html>

+ 21 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery-ui-demo-ie8.css

@@ -0,0 +1,21 @@
+@charset "UTF-8";
+/*
+ * jQuery File Upload Demo CSS Fixes for IE<9
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+.navigation {
+  list-style: none;
+  padding: 0;
+  margin: 1em 0;
+}
+.navigation li {
+  display: inline;
+  margin-right: 10px;
+}

+ 67 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery-ui-demo.css

@@ -0,0 +1,67 @@
+@charset "UTF-8";
+/*
+ * jQuery File Upload Demo CSS
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+body {
+  max-width: 750px;
+  margin: 0 auto;
+  padding: 1em;
+  font-family: "Lucida Grande", "Lucida Sans Unicode", Arial, sans-serif;
+  font-size: 1em;
+  line-height: 1.4em;
+  background: #222;
+  color: #fff;
+  -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+}
+a {
+  color: orange;
+  text-decoration: none;
+}
+img {
+  border: 0;
+  vertical-align: middle;
+}
+h1 {
+  line-height: 1em;
+}
+blockquote {
+  padding: 0 0 0 15px;
+  margin: 0 0 20px;
+  border-left: 5px solid #eee;
+}
+table {
+  width: 100%;
+  margin: 10px 0;
+}
+
+.fileupload-progress {
+	margin: 10px 0;
+}
+.fileupload-progress .progress-extended {
+	margin-top: 5px;
+}
+.error {
+  color: red;
+}
+
+@media (min-width: 481px) {
+  .navigation {
+    list-style: none;
+    padding: 0;
+  }
+  .navigation li {
+    display: inline-block;
+  }
+  .navigation li:not(:first-child):before {
+    content: "| ";
+  }
+}

+ 22 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-noscript.css

@@ -0,0 +1,22 @@
+@charset "UTF-8";
+/*
+ * jQuery File Upload Plugin NoScript CSS
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+.fileinput-button input {
+  position: static;
+  opacity: 1;
+  filter: none;
+  font-size: inherit !important;
+  direction: inherit;
+}
+.fileinput-button span {
+  display: none;
+}

+ 17 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-ui-noscript.css

@@ -0,0 +1,17 @@
+@charset "UTF-8";
+/*
+ * jQuery File Upload UI Plugin NoScript CSS
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2012, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+.fileinput-button i,
+.fileupload-buttonbar .delete,
+.fileupload-buttonbar .toggle {
+  display: none;
+}

+ 57 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload-ui.css

@@ -0,0 +1,57 @@
+@charset "UTF-8";
+/*
+ * jQuery File Upload UI Plugin CSS
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+.fileupload-buttonbar .btn,
+.fileupload-buttonbar .toggle {
+  margin-bottom: 5px;
+}
+.progress-animated .progress-bar,
+.progress-animated .bar {
+  background: url("../img/progressbar.gif") !important;
+  filter: none;
+}
+.fileupload-process {
+  float: right;
+  display: none;
+}
+.fileupload-processing .fileupload-process,
+.files .processing .preview {
+  display: block;
+  width: 32px;
+  height: 32px;
+  background: url("../img/loading.gif") center no-repeat;
+  background-size: contain;
+}
+.files audio,
+.files video {
+  max-width: 300px;
+}
+
+@media (max-width: 767px) {
+  .fileupload-buttonbar .toggle,
+  .files .toggle,
+  .files .btn span {
+    display: none;
+  }
+  .files .name {
+    width: 80px;
+    word-wrap: break-word;
+  }
+  .files audio,
+  .files video {
+    max-width: 80px;
+  }
+  .files img,
+  .files canvas {
+    max-width: 100%;
+  }
+}

+ 37 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/jquery.fileupload.css

@@ -0,0 +1,37 @@
+@charset "UTF-8";
+/*
+ * jQuery File Upload Plugin CSS
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+.fileinput-button {
+  position: relative;
+  overflow: hidden;
+  display: inline-block;
+}
+.fileinput-button input {
+  position: absolute;
+  top: 0;
+  right: 0;
+  margin: 0;
+  opacity: 0;
+  -ms-filter: 'alpha(opacity=0)';
+  font-size: 200px !important;
+  direction: ltr;
+  cursor: pointer;
+}
+
+/* Fixes for IE < 8 */
+@media screen\9 {
+  .fileinput-button input {
+    filter: alpha(opacity=0);
+    font-size: 100%;
+    height: 100%;
+  }
+}

+ 15 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/css/style.css

@@ -0,0 +1,15 @@
+@charset "UTF-8";
+/*
+ * jQuery File Upload Plugin CSS Example
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+body {
+  padding-top: 60px;
+}

二进制
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/img/loading.gif


二进制
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/img/progressbar.gif


+ 255 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/index.html

@@ -0,0 +1,255 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery File Upload Plugin Demo
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<!-- Force latest IE rendering engine or ChromeFrame if installed -->
+<!--[if IE]>
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<![endif]-->
+<meta charset="utf-8">
+<title>jQuery File Upload Demo</title>
+<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<!-- Bootstrap styles -->
+<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+<!-- Generic page styles -->
+<link rel="stylesheet" href="css/style.css">
+<!-- blueimp Gallery styles -->
+<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
+<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
+<link rel="stylesheet" href="css/jquery.fileupload.css">
+<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
+<!-- CSS adjustments for browsers with JavaScript disabled -->
+<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
+<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
+</head>
+<body>
+<div class="navbar navbar-default navbar-fixed-top">
+    <div class="container">
+        <div class="navbar-header">
+            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
+        </div>
+        <div class="navbar-collapse collapse">
+            <ul class="nav navbar-nav">
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
+                <li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
+                <li><a href="https://blueimp.net">&copy; Sebastian Tschan</a></li>
+            </ul>
+        </div>
+    </div>
+</div>
+<div class="container">
+    <h1>jQuery File Upload Demo</h1>
+    <h2 class="lead">Basic Plus UI version</h2>
+    <ul class="nav nav-tabs">
+        <li><a href="basic.html">Basic</a></li>
+        <li><a href="basic-plus.html">Basic Plus</a></li>
+        <li class="active"><a href="index.html">Basic Plus UI</a></li>
+        <li><a href="angularjs.html">AngularJS</a></li>
+        <li><a href="jquery-ui.html">jQuery UI</a></li>
+    </ul>
+    <br>
+    <blockquote>
+        <p>File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery.<br>
+        Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
+        Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
+    </blockquote>
+    <br>
+    <!-- The file upload form used as target for the file upload widget -->
+    <form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
+        <!-- Redirect browsers with JavaScript disabled to the origin page -->
+        <noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
+        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
+        <div class="row fileupload-buttonbar">
+            <div class="col-lg-7">
+                <!-- The fileinput-button span is used to style the file input field as button -->
+                <span class="btn btn-success fileinput-button">
+                    <i class="glyphicon glyphicon-plus"></i>
+                    <span>Add files...</span>
+                    <input type="file" name="files[]" multiple>
+                </span>
+                <button type="submit" class="btn btn-primary start">
+                    <i class="glyphicon glyphicon-upload"></i>
+                    <span>Start upload</span>
+                </button>
+                <button type="reset" class="btn btn-warning cancel">
+                    <i class="glyphicon glyphicon-ban-circle"></i>
+                    <span>Cancel upload</span>
+                </button>
+                <button type="button" class="btn btn-danger delete">
+                    <i class="glyphicon glyphicon-trash"></i>
+                    <span>Delete</span>
+                </button>
+                <input type="checkbox" class="toggle">
+                <!-- The global file processing state -->
+                <span class="fileupload-process"></span>
+            </div>
+            <!-- The global progress state -->
+            <div class="col-lg-5 fileupload-progress fade">
+                <!-- The global progress bar -->
+                <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
+                    <div class="progress-bar progress-bar-success" style="width:0%;"></div>
+                </div>
+                <!-- The extended global progress state -->
+                <div class="progress-extended">&nbsp;</div>
+            </div>
+        </div>
+        <!-- The table listing the files available for upload/download -->
+        <table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
+    </form>
+    <br>
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h3 class="panel-title">Demo Notes</h3>
+        </div>
+        <div class="panel-body">
+            <ul>
+                <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
+                <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
+                <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
+                <li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
+                <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
+                <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
+            </ul>
+        </div>
+    </div>
+</div>
+<!-- The blueimp Gallery widget -->
+<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
+    <div class="slides"></div>
+    <h3 class="title"></h3>
+    <a class="prev">‹</a>
+    <a class="next">›</a>
+    <a class="close">×</a>
+    <a class="play-pause"></a>
+    <ol class="indicator"></ol>
+</div>
+<!-- The template to display files available for upload -->
+<script id="template-upload" type="text/x-tmpl">
+{% for (var i=0, file; file=o.files[i]; i++) { %}
+    <tr class="template-upload fade">
+        <td>
+            <span class="preview"></span>
+        </td>
+        <td>
+            <p class="name">{%=file.name%}</p>
+            <strong class="error text-danger"></strong>
+        </td>
+        <td>
+            <p class="size">Processing...</p>
+            <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
+        </td>
+        <td>
+            {% if (!i && !o.options.autoUpload) { %}
+                <button class="btn btn-primary start" disabled>
+                    <i class="glyphicon glyphicon-upload"></i>
+                    <span>Start</span>
+                </button>
+            {% } %}
+            {% if (!i) { %}
+                <button class="btn btn-warning cancel">
+                    <i class="glyphicon glyphicon-ban-circle"></i>
+                    <span>Cancel</span>
+                </button>
+            {% } %}
+        </td>
+    </tr>
+{% } %}
+</script>
+<!-- The template to display files available for download -->
+<script id="template-download" type="text/x-tmpl">
+{% for (var i=0, file; file=o.files[i]; i++) { %}
+    <tr class="template-download fade">
+        <td>
+            <span class="preview">
+                {% if (file.thumbnailUrl) { %}
+                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
+                {% } %}
+            </span>
+        </td>
+        <td>
+            <p class="name">
+                {% if (file.url) { %}
+                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
+                {% } else { %}
+                    <span>{%=file.name%}</span>
+                {% } %}
+            </p>
+            {% if (file.error) { %}
+                <div><span class="label label-danger">Error</span> {%=file.error%}</div>
+            {% } %}
+        </td>
+        <td>
+            <span class="size">{%=o.formatFileSize(file.size)%}</span>
+        </td>
+        <td>
+            {% if (file.deleteUrl) { %}
+                <button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
+                    <i class="glyphicon glyphicon-trash"></i>
+                    <span>Delete</span>
+                </button>
+                <input type="checkbox" name="delete" value="1" class="toggle">
+            {% } else { %}
+                <button class="btn btn-warning cancel">
+                    <i class="glyphicon glyphicon-ban-circle"></i>
+                    <span>Cancel</span>
+                </button>
+            {% } %}
+        </td>
+    </tr>
+{% } %}
+</script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
+<script src="js/vendor/jquery.ui.widget.js"></script>
+<!-- The Templates plugin is included to render the upload/download listings -->
+<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
+<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<!-- The Canvas to Blob plugin is included for image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
+<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+<!-- blueimp Gallery script -->
+<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
+<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
+<script src="js/jquery.iframe-transport.js"></script>
+<!-- The basic File Upload plugin -->
+<script src="js/jquery.fileupload.js"></script>
+<!-- The File Upload processing plugin -->
+<script src="js/jquery.fileupload-process.js"></script>
+<!-- The File Upload image preview & resize plugin -->
+<script src="js/jquery.fileupload-image.js"></script>
+<!-- The File Upload audio preview plugin -->
+<script src="js/jquery.fileupload-audio.js"></script>
+<!-- The File Upload video preview plugin -->
+<script src="js/jquery.fileupload-video.js"></script>
+<!-- The File Upload validation plugin -->
+<script src="js/jquery.fileupload-validate.js"></script>
+<!-- The File Upload user interface plugin -->
+<script src="js/jquery.fileupload-ui.js"></script>
+<!-- The main application script -->
+<script src="js/main.js"></script>
+<!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
+<!--[if (gte IE 8)&(lt IE 10)]>
+<script src="js/cors/jquery.xdr-transport.js"></script>
+<![endif]-->
+</body>
+</html>

+ 252 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/jquery-ui.html

@@ -0,0 +1,252 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery File Upload Plugin jQuery UI Demo
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<!-- Force latest IE rendering engine or ChromeFrame if installed -->
+<!--[if IE]>
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<![endif]-->
+<meta charset="utf-8">
+<title>jQuery File Upload Demo - jQuery UI version</title>
+<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<!-- jQuery UI styles -->
+<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/dark-hive/jquery-ui.css" id="theme">
+<!-- Generic page styles -->
+<link rel="stylesheet" href="css/style.css">
+<!-- Demo styles -->
+<link rel="stylesheet" href="css/jquery-ui-demo.css">
+<!--[if lte IE 8]>
+<link rel="stylesheet" href="css/jquery-ui-demo-ie8.css">
+<![endif]-->
+<style>
+/* Adjust the jQuery UI widget font-size: */
+.ui-widget {
+    font-size: 0.95em;
+}
+</style>
+<!-- blueimp Gallery styles -->
+<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
+<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
+<link rel="stylesheet" href="css/jquery.fileupload.css">
+<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
+<!-- CSS adjustments for browsers with JavaScript disabled -->
+<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
+<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
+</head>
+<body>
+<ul class="navigation">
+    <li><h3><a href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a></h3></li>
+    <li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
+    <li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
+    <li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
+    <li><a href="https://blueimp.net">&copy; blueimp.net</a></li>
+</ul>
+<h1>jQuery File Upload Demo</h1>
+<h2>jQuery UI version</h2>
+<form>
+    <label for="theme-switcher">Theme:</label>
+    <select id="theme-switcher" class="pull-right">
+        <option value="black-tie">Black Tie</option>
+        <option value="blitzer">Blitzer</option>
+        <option value="cupertino">Cupertino</option>
+        <option value="dark-hive" selected>Dark Hive</option>
+        <option value="dot-luv">Dot Luv</option>
+        <option value="eggplant">Eggplant</option>
+        <option value="excite-bike">Excite Bike</option>
+        <option value="flick">Flick</option>
+        <option value="hot-sneaks">Hot sneaks</option>
+        <option value="humanity">Humanity</option>
+        <option value="le-frog">Le Frog</option>
+        <option value="mint-choc">Mint Choc</option>
+        <option value="overcast">Overcast</option>
+        <option value="pepper-grinder">Pepper Grinder</option>
+        <option value="redmond">Redmond</option>
+        <option value="smoothness">Smoothness</option>
+        <option value="south-street">South Street</option>
+        <option value="start">Start</option>
+        <option value="sunny">Sunny</option>
+        <option value="swanky-purse">Swanky Purse</option>
+        <option value="trontastic">Trontastic</option>
+        <option value="ui-darkness">UI Darkness</option>
+        <option value="ui-lightness">UI Lightness</option>
+        <option value="vader">Vader</option>
+    </select>
+</form>
+<ul class="navigation">
+    <li><a href="basic.html">Basic</a></li>
+    <li><a href="basic-plus.html">Basic Plus</a></li>
+    <li><a href="index.html">Basic Plus UI</a></li>
+    <li><a href="angularjs.html">AngularJS</a></li>
+    <li class="active"><a href="jquery-ui.html">jQuery UI</a></li>
+</ul>
+<blockquote>
+    <p>File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery UI.<br>
+    Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
+    Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
+</blockquote>
+<!-- The file upload form used as target for the file upload widget -->
+<form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
+    <!-- Redirect browsers with JavaScript disabled to the origin page -->
+    <noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
+    <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
+    <div class="fileupload-buttonbar">
+        <div class="fileupload-buttons">
+            <!-- The fileinput-button span is used to style the file input field as button -->
+            <span class="fileinput-button">
+                <span>Add files...</span>
+                <input type="file" name="files[]" multiple>
+            </span>
+            <button type="submit" class="start">Start upload</button>
+            <button type="reset" class="cancel">Cancel upload</button>
+            <button type="button" class="delete">Delete</button>
+            <input type="checkbox" class="toggle">
+            <!-- The global file processing state -->
+            <span class="fileupload-process"></span>
+        </div>
+        <!-- The global progress state -->
+        <div class="fileupload-progress fade" style="display:none">
+            <!-- The global progress bar -->
+            <div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100"></div>
+            <!-- The extended global progress state -->
+            <div class="progress-extended">&nbsp;</div>
+        </div>
+    </div>
+    <!-- The table listing the files available for upload/download -->
+    <table role="presentation"><tbody class="files"></tbody></table>
+</form>
+<br>
+<h3>Demo Notes</h3>
+<ul>
+    <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
+    <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
+    <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
+    <li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
+    <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
+    <li>Built with <a href="https://jqueryui.com">jQuery UI</a>.</li>
+</ul>
+<!-- The blueimp Gallery widget -->
+<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
+    <div class="slides"></div>
+    <h3 class="title"></h3>
+    <a class="prev">‹</a>
+    <a class="next">›</a>
+    <a class="close">×</a>
+    <a class="play-pause"></a>
+    <ol class="indicator"></ol>
+</div>
+<!-- The template to display files available for upload -->
+<script id="template-upload" type="text/x-tmpl">
+{% for (var i=0, file; file=o.files[i]; i++) { %}
+    <tr class="template-upload fade">
+        <td>
+            <span class="preview"></span>
+        </td>
+        <td>
+            <p class="name">{%=file.name%}</p>
+            <strong class="error"></strong>
+        </td>
+        <td>
+            <p class="size">Processing...</p>
+            <div class="progress"></div>
+        </td>
+        <td>
+            {% if (!i && !o.options.autoUpload) { %}
+                <button class="start" disabled>Start</button>
+            {% } %}
+            {% if (!i) { %}
+                <button class="cancel">Cancel</button>
+            {% } %}
+        </td>
+    </tr>
+{% } %}
+</script>
+<!-- The template to display files available for download -->
+<script id="template-download" type="text/x-tmpl">
+{% for (var i=0, file; file=o.files[i]; i++) { %}
+    <tr class="template-download fade">
+        <td>
+            <span class="preview">
+                {% if (file.thumbnailUrl) { %}
+                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
+                {% } %}
+            </span>
+        </td>
+        <td>
+            <p class="name">
+                <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
+            </p>
+            {% if (file.error) { %}
+                <div><span class="error">Error</span> {%=file.error%}</div>
+            {% } %}
+        </td>
+        <td>
+            <span class="size">{%=o.formatFileSize(file.size)%}</span>
+        </td>
+        <td>
+            <button class="delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>Delete</button>
+            <input type="checkbox" name="delete" value="1" class="toggle">
+        </td>
+    </tr>
+{% } %}
+</script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
+<!-- The Templates plugin is included to render the upload/download listings -->
+<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
+<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<!-- The Canvas to Blob plugin is included for image resizing functionality -->
+<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<!-- blueimp Gallery script -->
+<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
+<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
+<script src="js/jquery.iframe-transport.js"></script>
+<!-- The basic File Upload plugin -->
+<script src="js/jquery.fileupload.js"></script>
+<!-- The File Upload processing plugin -->
+<script src="js/jquery.fileupload-process.js"></script>
+<!-- The File Upload image preview & resize plugin -->
+<script src="js/jquery.fileupload-image.js"></script>
+<!-- The File Upload audio preview plugin -->
+<script src="js/jquery.fileupload-audio.js"></script>
+<!-- The File Upload video preview plugin -->
+<script src="js/jquery.fileupload-video.js"></script>
+<!-- The File Upload validation plugin -->
+<script src="js/jquery.fileupload-validate.js"></script>
+<!-- The File Upload user interface plugin -->
+<script src="js/jquery.fileupload-ui.js"></script>
+<!-- The File Upload jQuery UI plugin -->
+<script src="js/jquery.fileupload-jquery-ui.js"></script>
+<!-- The main application script -->
+<script src="js/main.js"></script>
+<script>
+// Initialize the jQuery UI theme switcher:
+$('#theme-switcher').change(function () {
+    var theme = $('#theme');
+    theme.prop(
+        'href',
+        theme.prop('href').replace(
+            /[\w\-]+\/jquery-ui.css/,
+            $(this).val() + '/jquery-ui.css'
+        )
+    );
+});
+</script>
+<!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
+<!--[if (gte IE 8)&(lt IE 10)]>
+<script src="js/cors/jquery.xdr-transport.js"></script>
+<![endif]-->
+</body>
+</html>

+ 101 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/app.js

@@ -0,0 +1,101 @@
+/*
+ * jQuery File Upload Plugin Angular JS Example
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global window, angular */
+
+;(function () {
+    'use strict';
+
+    var isOnGitHub = window.location.hostname === 'blueimp.github.io',
+        url = isOnGitHub ? '//jquery-file-upload.appspot.com/' : 'server/php/';
+
+    angular.module('demo', [
+        'blueimp.fileupload'
+    ])
+        .config([
+            '$httpProvider', 'fileUploadProvider',
+            function ($httpProvider, fileUploadProvider) {
+                delete $httpProvider.defaults.headers.common['X-Requested-With'];
+                fileUploadProvider.defaults.redirect = window.location.href.replace(
+                    /\/[^\/]*$/,
+                    '/cors/result.html?%s'
+                );
+                if (isOnGitHub) {
+                    // Demo settings:
+                    angular.extend(fileUploadProvider.defaults, {
+                        // Enable image resizing, except for Android and Opera,
+                        // which actually support image resizing, but fail to
+                        // send Blob objects via XHR requests:
+                        disableImageResize: /Android(?!.*Chrome)|Opera/
+                            .test(window.navigator.userAgent),
+                        maxFileSize: 999000,
+                        acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
+                    });
+                }
+            }
+        ])
+
+        .controller('DemoFileUploadController', [
+            '$scope', '$http', '$filter', '$window',
+            function ($scope, $http) {
+                $scope.options = {
+                    url: url
+                };
+                if (!isOnGitHub) {
+                    $scope.loadingFiles = true;
+                    $http.get(url)
+                        .then(
+                            function (response) {
+                                $scope.loadingFiles = false;
+                                $scope.queue = response.data.files || [];
+                            },
+                            function () {
+                                $scope.loadingFiles = false;
+                            }
+                        );
+                }
+            }
+        ])
+
+        .controller('FileDestroyController', [
+            '$scope', '$http',
+            function ($scope, $http) {
+                var file = $scope.file,
+                    state;
+                if (file.url) {
+                    file.$state = function () {
+                        return state;
+                    };
+                    file.$destroy = function () {
+                        state = 'pending';
+                        return $http({
+                            url: file.deleteUrl,
+                            method: file.deleteType
+                        }).then(
+                            function () {
+                                state = 'resolved';
+                                $scope.clear(file);
+                            },
+                            function () {
+                                state = 'rejected';
+                            }
+                        );
+                    };
+                } else if (!file.$cancel && !file._index) {
+                    file.$cancel = function () {
+                        $scope.clear(file);
+                    };
+                }
+            }
+        ]);
+
+}());

+ 126 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/cors/jquery.postmessage-transport.js

@@ -0,0 +1,126 @@
+/*
+ * jQuery postMessage Transport Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* global define, require, window, document */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define(['jquery'], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(require('jquery'));
+    } else {
+        // Browser globals:
+        factory(window.jQuery);
+    }
+}(function ($) {
+    'use strict';
+
+    var counter = 0,
+        names = [
+            'accepts',
+            'cache',
+            'contents',
+            'contentType',
+            'crossDomain',
+            'data',
+            'dataType',
+            'headers',
+            'ifModified',
+            'mimeType',
+            'password',
+            'processData',
+            'timeout',
+            'traditional',
+            'type',
+            'url',
+            'username'
+        ],
+        convert = function (p) {
+            return p;
+        };
+
+    $.ajaxSetup({
+        converters: {
+            'postmessage text': convert,
+            'postmessage json': convert,
+            'postmessage html': convert
+        }
+    });
+
+    $.ajaxTransport('postmessage', function (options) {
+        if (options.postMessage && window.postMessage) {
+            var iframe,
+                loc = $('<a>').prop('href', options.postMessage)[0],
+                target = loc.protocol + '//' + loc.host,
+                xhrUpload = options.xhr().upload;
+            // IE always includes the port for the host property of a link
+            // element, but not in the location.host or origin property for the
+            // default http port 80 and https port 443, so we strip it:
+            if (/^(http:\/\/.+:80)|(https:\/\/.+:443)$/.test(target)) {
+              target = target.replace(/:(80|443)$/, '');
+            }
+            return {
+                send: function (_, completeCallback) {
+                    counter += 1;
+                    var message = {
+                            id: 'postmessage-transport-' + counter
+                        },
+                        eventName = 'message.' + message.id;
+                    iframe = $(
+                        '<iframe style="display:none;" src="' +
+                            options.postMessage + '" name="' +
+                            message.id + '"></iframe>'
+                    ).bind('load', function () {
+                        $.each(names, function (i, name) {
+                            message[name] = options[name];
+                        });
+                        message.dataType = message.dataType.replace('postmessage ', '');
+                        $(window).bind(eventName, function (e) {
+                            e = e.originalEvent;
+                            var data = e.data,
+                                ev;
+                            if (e.origin === target && data.id === message.id) {
+                                if (data.type === 'progress') {
+                                    ev = document.createEvent('Event');
+                                    ev.initEvent(data.type, false, true);
+                                    $.extend(ev, data);
+                                    xhrUpload.dispatchEvent(ev);
+                                } else {
+                                    completeCallback(
+                                        data.status,
+                                        data.statusText,
+                                        {postmessage: data.result},
+                                        data.headers
+                                    );
+                                    iframe.remove();
+                                    $(window).unbind(eventName);
+                                }
+                            }
+                        });
+                        iframe[0].contentWindow.postMessage(
+                            message,
+                            target
+                        );
+                    }).appendTo(document.body);
+                },
+                abort: function () {
+                    if (iframe) {
+                        iframe.remove();
+                    }
+                }
+            };
+        }
+    });
+
+}));

+ 89 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/cors/jquery.xdr-transport.js

@@ -0,0 +1,89 @@
+/*
+ * jQuery XDomainRequest Transport Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ *
+ * Based on Julian Aubourg's ajaxHooks xdr.js:
+ * https://github.com/jaubourg/ajaxHooks/
+ */
+
+/* global define, require, window, XDomainRequest */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define(['jquery'], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(require('jquery'));
+    } else {
+        // Browser globals:
+        factory(window.jQuery);
+    }
+}(function ($) {
+    'use strict';
+    if (window.XDomainRequest && !$.support.cors) {
+        $.ajaxTransport(function (s) {
+            if (s.crossDomain && s.async) {
+                if (s.timeout) {
+                    s.xdrTimeout = s.timeout;
+                    delete s.timeout;
+                }
+                var xdr;
+                return {
+                    send: function (headers, completeCallback) {
+                        var addParamChar = /\?/.test(s.url) ? '&' : '?';
+                        function callback(status, statusText, responses, responseHeaders) {
+                            xdr.onload = xdr.onerror = xdr.ontimeout = $.noop;
+                            xdr = null;
+                            completeCallback(status, statusText, responses, responseHeaders);
+                        }
+                        xdr = new XDomainRequest();
+                        // XDomainRequest only supports GET and POST:
+                        if (s.type === 'DELETE') {
+                            s.url = s.url + addParamChar + '_method=DELETE';
+                            s.type = 'POST';
+                        } else if (s.type === 'PUT') {
+                            s.url = s.url + addParamChar + '_method=PUT';
+                            s.type = 'POST';
+                        } else if (s.type === 'PATCH') {
+                            s.url = s.url + addParamChar + '_method=PATCH';
+                            s.type = 'POST';
+                        }
+                        xdr.open(s.type, s.url);
+                        xdr.onload = function () {
+                            callback(
+                                200,
+                                'OK',
+                                {text: xdr.responseText},
+                                'Content-Type: ' + xdr.contentType
+                            );
+                        };
+                        xdr.onerror = function () {
+                            callback(404, 'Not Found');
+                        };
+                        if (s.xdrTimeout) {
+                            xdr.ontimeout = function () {
+                                callback(0, 'timeout');
+                            };
+                            xdr.timeout = s.xdrTimeout;
+                        }
+                        xdr.send((s.hasContent && s.data) || null);
+                    },
+                    abort: function () {
+                        if (xdr) {
+                            xdr.onerror = $.noop();
+                            xdr.abort();
+                        }
+                    }
+                };
+            }
+        });
+    }
+}));

+ 437 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-angular.js

@@ -0,0 +1,437 @@
+/*
+ * jQuery File Upload AngularJS Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, angular, require */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            'angular',
+            './jquery.fileupload-image',
+            './jquery.fileupload-audio',
+            './jquery.fileupload-video',
+            './jquery.fileupload-validate'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('angular'),
+            require('./jquery.fileupload-image'),
+            require('./jquery.fileupload-audio'),
+            require('./jquery.fileupload-video'),
+            require('./jquery.fileupload-validate')
+        );
+    } else {
+        factory();
+    }
+}(function () {
+    'use strict';
+
+    angular.module('blueimp.fileupload', [])
+
+        // The fileUpload service provides configuration options
+        // for the fileUpload directive and default handlers for
+        // File Upload events:
+        .provider('fileUpload', function () {
+            var scopeEvalAsync = function (expression) {
+                    var scope = angular.element(this)
+                            .fileupload('option', 'scope');
+                    // Schedule a new $digest cycle if not already inside of one
+                    // and evaluate the given expression:
+                    scope.$evalAsync(expression);
+                },
+                addFileMethods = function (scope, data) {
+                    var files = data.files,
+                        file = files[0];
+                    angular.forEach(files, function (file, index) {
+                        file._index = index;
+                        file.$state = function () {
+                            return data.state();
+                        };
+                        file.$processing = function () {
+                            return data.processing();
+                        };
+                        file.$progress = function () {
+                            return data.progress();
+                        };
+                        file.$response = function () {
+                            return data.response();
+                        };
+                    });
+                    file.$submit = function () {
+                        if (!file.error) {
+                            return data.submit();
+                        }
+                    };
+                    file.$cancel = function () {
+                        return data.abort();
+                    };
+                },
+                $config;
+            $config = this.defaults = {
+                handleResponse: function (e, data) {
+                    var files = data.result && data.result.files;
+                    if (files) {
+                        data.scope.replace(data.files, files);
+                    } else if (data.errorThrown ||
+                            data.textStatus === 'error') {
+                        data.files[0].error = data.errorThrown ||
+                            data.textStatus;
+                    }
+                },
+                add: function (e, data) {
+                    if (e.isDefaultPrevented()) {
+                        return false;
+                    }
+                    var scope = data.scope,
+                        filesCopy = [];
+                    angular.forEach(data.files, function (file) {
+                        filesCopy.push(file);
+                    });
+                    scope.$parent.$applyAsync(function () {
+                        addFileMethods(scope, data);
+                        var method = scope.option('prependFiles') ?
+                                'unshift' : 'push';
+                        Array.prototype[method].apply(scope.queue, data.files);
+                    });
+                    data.process(function () {
+                        return scope.process(data);
+                    }).always(function () {
+                        scope.$parent.$applyAsync(function () {
+                            addFileMethods(scope, data);
+                            scope.replace(filesCopy, data.files);
+                        });
+                    }).then(function () {
+                        if ((scope.option('autoUpload') ||
+                                data.autoUpload) &&
+                                data.autoUpload !== false) {
+                            data.submit();
+                        }
+                    });
+                },
+                done: function (e, data) {
+                    if (e.isDefaultPrevented()) {
+                        return false;
+                    }
+                    var that = this;
+                    data.scope.$apply(function () {
+                        data.handleResponse.call(that, e, data);
+                    });
+                },
+                fail: function (e, data) {
+                    if (e.isDefaultPrevented()) {
+                        return false;
+                    }
+                    var that = this,
+                        scope = data.scope;
+                    if (data.errorThrown === 'abort') {
+                        scope.clear(data.files);
+                        return;
+                    }
+                    scope.$apply(function () {
+                        data.handleResponse.call(that, e, data);
+                    });
+                },
+                stop: scopeEvalAsync,
+                processstart: scopeEvalAsync,
+                processstop: scopeEvalAsync,
+                getNumberOfFiles: function () {
+                    var scope = this.scope;
+                    return scope.queue.length - scope.processing();
+                },
+                dataType: 'json',
+                autoUpload: false
+            };
+            this.$get = [
+                function () {
+                    return {
+                        defaults: $config
+                    };
+                }
+            ];
+        })
+
+        // Format byte numbers to readable presentations:
+        .provider('formatFileSizeFilter', function () {
+            var $config = {
+                // Byte units following the IEC format
+                // http://en.wikipedia.org/wiki/Kilobyte
+                units: [
+                    {size: 1000000000, suffix: ' GB'},
+                    {size: 1000000, suffix: ' MB'},
+                    {size: 1000, suffix: ' KB'}
+                ]
+            };
+            this.defaults = $config;
+            this.$get = function () {
+                return function (bytes) {
+                    if (!angular.isNumber(bytes)) {
+                        return '';
+                    }
+                    var unit = true,
+                        i = 0,
+                        prefix,
+                        suffix;
+                    while (unit) {
+                        unit = $config.units[i];
+                        prefix = unit.prefix || '';
+                        suffix = unit.suffix || '';
+                        if (i === $config.units.length - 1 || bytes >= unit.size) {
+                            return prefix + (bytes / unit.size).toFixed(2) + suffix;
+                        }
+                        i += 1;
+                    }
+                };
+            };
+        })
+
+        // The FileUploadController initializes the fileupload widget and
+        // provides scope methods to control the File Upload functionality:
+        .controller('FileUploadController', [
+            '$scope', '$element', '$attrs', '$window', 'fileUpload','$q',
+            function ($scope, $element, $attrs, $window, fileUpload, $q) {
+                var uploadMethods = {
+                    progress: function () {
+                        return $element.fileupload('progress');
+                    },
+                    active: function () {
+                        return $element.fileupload('active');
+                    },
+                    option: function (option, data) {
+                        if (arguments.length === 1) {
+                            return $element.fileupload('option', option);
+                        }
+                        $element.fileupload('option', option, data);
+                    },
+                    add: function (data) {
+                        return $element.fileupload('add', data);
+                    },
+                    send: function (data) {
+                        return $element.fileupload('send', data);
+                    },
+                    process: function (data) {
+                        return $element.fileupload('process', data);
+                    },
+                    processing: function (data) {
+                        return $element.fileupload('processing', data);
+                    }
+                };
+                $scope.disabled = !$window.jQuery.support.fileInput;
+                $scope.queue = $scope.queue || [];
+                $scope.clear = function (files) {
+                    var queue = this.queue,
+                        i = queue.length,
+                        file = files,
+                        length = 1;
+                    if (angular.isArray(files)) {
+                        file = files[0];
+                        length = files.length;
+                    }
+                    while (i) {
+                        i -= 1;
+                        if (queue[i] === file) {
+                            return queue.splice(i, length);
+                        }
+                    }
+                };
+                $scope.replace = function (oldFiles, newFiles) {
+                    var queue = this.queue,
+                        file = oldFiles[0],
+                        i,
+                        j;
+                    for (i = 0; i < queue.length; i += 1) {
+                        if (queue[i] === file) {
+                            for (j = 0; j < newFiles.length; j += 1) {
+                                queue[i + j] = newFiles[j];
+                            }
+                            return;
+                        }
+                    }
+                };
+                $scope.applyOnQueue = function (method) {
+                    var list = this.queue.slice(0),
+                        i,
+                        file,
+                        promises = [];
+                    for (i = 0; i < list.length; i += 1) {
+                        file = list[i];
+                        if (file[method]) {
+                            promises.push(file[method]());
+                        }
+                    }
+                    return $q.all(promises);
+                };
+                $scope.submit = function () {
+                    return this.applyOnQueue('$submit');
+                };
+                $scope.cancel = function () {
+                    return this.applyOnQueue('$cancel');
+                };
+                // Add upload methods to the scope:
+                angular.extend($scope, uploadMethods);
+                // The fileupload widget will initialize with
+                // the options provided via "data-"-parameters,
+                // as well as those given via options object:
+                $element.fileupload(angular.extend(
+                    {scope: $scope},
+                    fileUpload.defaults
+                )).on('fileuploadadd', function (e, data) {
+                    data.scope = $scope;
+                }).on('fileuploadfail', function (e, data) {
+                    if (data.errorThrown === 'abort') {
+                        return;
+                    }
+                    if (data.dataType &&
+                            data.dataType.indexOf('json') === data.dataType.length - 4) {
+                        try {
+                            data.result = angular.fromJson(data.jqXHR.responseText);
+                        } catch (ignore) {}
+                    }
+                }).on([
+                    'fileuploadadd',
+                    'fileuploadsubmit',
+                    'fileuploadsend',
+                    'fileuploaddone',
+                    'fileuploadfail',
+                    'fileuploadalways',
+                    'fileuploadprogress',
+                    'fileuploadprogressall',
+                    'fileuploadstart',
+                    'fileuploadstop',
+                    'fileuploadchange',
+                    'fileuploadpaste',
+                    'fileuploaddrop',
+                    'fileuploaddragover',
+                    'fileuploadchunksend',
+                    'fileuploadchunkdone',
+                    'fileuploadchunkfail',
+                    'fileuploadchunkalways',
+                    'fileuploadprocessstart',
+                    'fileuploadprocess',
+                    'fileuploadprocessdone',
+                    'fileuploadprocessfail',
+                    'fileuploadprocessalways',
+                    'fileuploadprocessstop'
+                ].join(' '), function (e, data) {
+                    $scope.$parent.$applyAsync(function () {
+                        if ($scope.$emit(e.type, data).defaultPrevented) {
+                            e.preventDefault();
+                        }
+                    });
+                }).on('remove', function () {
+                    // Remove upload methods from the scope,
+                    // when the widget is removed:
+                    var method;
+                    for (method in uploadMethods) {
+                        if (uploadMethods.hasOwnProperty(method)) {
+                            delete $scope[method];
+                        }
+                    }
+                });
+                // Observe option changes:
+                $scope.$watch(
+                    $attrs.fileUpload,
+                    function (newOptions) {
+                        if (newOptions) {
+                            $element.fileupload('option', newOptions);
+                        }
+                    }
+                );
+            }
+        ])
+
+        // Provide File Upload progress feedback:
+        .controller('FileUploadProgressController', [
+            '$scope', '$attrs', '$parse',
+            function ($scope, $attrs, $parse) {
+                var fn = $parse($attrs.fileUploadProgress),
+                    update = function () {
+                        var progress = fn($scope);
+                        if (!progress || !progress.total) {
+                            return;
+                        }
+                        $scope.num = Math.floor(
+                            progress.loaded / progress.total * 100
+                        );
+                    };
+                update();
+                $scope.$watch(
+                    $attrs.fileUploadProgress + '.loaded',
+                    function (newValue, oldValue) {
+                        if (newValue !== oldValue) {
+                            update();
+                        }
+                    }
+                );
+            }
+        ])
+
+        // Display File Upload previews:
+        .controller('FileUploadPreviewController', [
+            '$scope', '$element', '$attrs',
+            function ($scope, $element, $attrs) {
+                $scope.$watch(
+                    $attrs.fileUploadPreview + '.preview',
+                    function (preview) {
+                        $element.empty();
+                        if (preview) {
+                            $element.append(preview);
+                        }
+                    }
+                );
+            }
+        ])
+
+        .directive('fileUpload', function () {
+            return {
+                controller: 'FileUploadController',
+                scope: true
+            };
+        })
+
+        .directive('fileUploadProgress', function () {
+            return {
+                controller: 'FileUploadProgressController',
+                scope: true
+            };
+        })
+
+        .directive('fileUploadPreview', function () {
+            return {
+                controller: 'FileUploadPreviewController'
+            };
+        })
+
+        // Enhance the HTML5 download attribute to
+        // allow drag&drop of files to the desktop:
+        .directive('download', function () {
+            return function (scope, elm) {
+                elm.on('dragstart', function (e) {
+                    try {
+                        e.originalEvent.dataTransfer.setData(
+                            'DownloadURL',
+                            [
+                                'application/octet-stream',
+                                elm.prop('download'),
+                                elm.prop('href')
+                            ].join(':')
+                        );
+                    } catch (ignore) {}
+                });
+            };
+        });
+
+}));

+ 113 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-audio.js

@@ -0,0 +1,113 @@
+/*
+ * jQuery File Upload Audio Preview Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window, document */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            'load-image',
+            './jquery.fileupload-process'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('blueimp-load-image/js/load-image'),
+            require('./jquery.fileupload-process')
+        );
+    } else {
+        // Browser globals:
+        factory(
+            window.jQuery,
+            window.loadImage
+        );
+    }
+}(function ($, loadImage) {
+    'use strict';
+
+    // Prepend to the default processQueue:
+    $.blueimp.fileupload.prototype.options.processQueue.unshift(
+        {
+            action: 'loadAudio',
+            // Use the action as prefix for the "@" options:
+            prefix: true,
+            fileTypes: '@',
+            maxFileSize: '@',
+            disabled: '@disableAudioPreview'
+        },
+        {
+            action: 'setAudio',
+            name: '@audioPreviewName',
+            disabled: '@disableAudioPreview'
+        }
+    );
+
+    // The File Upload Audio Preview plugin extends the fileupload widget
+    // with audio preview functionality:
+    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
+
+        options: {
+            // The regular expression for the types of audio files to load,
+            // matched against the file type:
+            loadAudioFileTypes: /^audio\/.*$/
+        },
+
+        _audioElement: document.createElement('audio'),
+
+        processActions: {
+
+            // Loads the audio file given via data.files and data.index
+            // as audio element if the browser supports playing it.
+            // Accepts the options fileTypes (regular expression)
+            // and maxFileSize (integer) to limit the files to load:
+            loadAudio: function (data, options) {
+                if (options.disabled) {
+                    return data;
+                }
+                var file = data.files[data.index],
+                    url,
+                    audio;
+                if (this._audioElement.canPlayType &&
+                        this._audioElement.canPlayType(file.type) &&
+                        ($.type(options.maxFileSize) !== 'number' ||
+                            file.size <= options.maxFileSize) &&
+                        (!options.fileTypes ||
+                            options.fileTypes.test(file.type))) {
+                    url = loadImage.createObjectURL(file);
+                    if (url) {
+                        audio = this._audioElement.cloneNode(false);
+                        audio.src = url;
+                        audio.controls = true;
+                        data.audio = audio;
+                        return data;
+                    }
+                }
+                return data;
+            },
+
+            // Sets the audio element as a property of the file object:
+            setAudio: function (data, options) {
+                if (data.audio && !options.disabled) {
+                    data.files[data.index][options.name || 'preview'] = data.audio;
+                }
+                return data;
+            }
+
+        }
+
+    });
+
+}));

+ 326 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-image.js

@@ -0,0 +1,326 @@
+/*
+ * jQuery File Upload Image Preview & Resize Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window, Blob */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            'load-image',
+            'load-image-meta',
+            'load-image-scale',
+            'load-image-exif',
+            'canvas-to-blob',
+            './jquery.fileupload-process'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('blueimp-load-image/js/load-image'),
+            require('blueimp-load-image/js/load-image-meta'),
+            require('blueimp-load-image/js/load-image-scale'),
+            require('blueimp-load-image/js/load-image-exif'),
+            require('blueimp-canvas-to-blob'),
+            require('./jquery.fileupload-process')
+        );
+    } else {
+        // Browser globals:
+        factory(
+            window.jQuery,
+            window.loadImage
+        );
+    }
+}(function ($, loadImage) {
+    'use strict';
+
+    // Prepend to the default processQueue:
+    $.blueimp.fileupload.prototype.options.processQueue.unshift(
+        {
+            action: 'loadImageMetaData',
+            disableImageHead: '@',
+            disableExif: '@',
+            disableExifThumbnail: '@',
+            disableExifSub: '@',
+            disableExifGps: '@',
+            disabled: '@disableImageMetaDataLoad'
+        },
+        {
+            action: 'loadImage',
+            // Use the action as prefix for the "@" options:
+            prefix: true,
+            fileTypes: '@',
+            maxFileSize: '@',
+            noRevoke: '@',
+            disabled: '@disableImageLoad'
+        },
+        {
+            action: 'resizeImage',
+            // Use "image" as prefix for the "@" options:
+            prefix: 'image',
+            maxWidth: '@',
+            maxHeight: '@',
+            minWidth: '@',
+            minHeight: '@',
+            crop: '@',
+            orientation: '@',
+            forceResize: '@',
+            disabled: '@disableImageResize'
+        },
+        {
+            action: 'saveImage',
+            quality: '@imageQuality',
+            type: '@imageType',
+            disabled: '@disableImageResize'
+        },
+        {
+            action: 'saveImageMetaData',
+            disabled: '@disableImageMetaDataSave'
+        },
+        {
+            action: 'resizeImage',
+            // Use "preview" as prefix for the "@" options:
+            prefix: 'preview',
+            maxWidth: '@',
+            maxHeight: '@',
+            minWidth: '@',
+            minHeight: '@',
+            crop: '@',
+            orientation: '@',
+            thumbnail: '@',
+            canvas: '@',
+            disabled: '@disableImagePreview'
+        },
+        {
+            action: 'setImage',
+            name: '@imagePreviewName',
+            disabled: '@disableImagePreview'
+        },
+        {
+            action: 'deleteImageReferences',
+            disabled: '@disableImageReferencesDeletion'
+        }
+    );
+
+    // The File Upload Resize plugin extends the fileupload widget
+    // with image resize functionality:
+    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
+
+        options: {
+            // The regular expression for the types of images to load:
+            // matched against the file type:
+            loadImageFileTypes: /^image\/(gif|jpeg|png|svg\+xml)$/,
+            // The maximum file size of images to load:
+            loadImageMaxFileSize: 10000000, // 10MB
+            // The maximum width of resized images:
+            imageMaxWidth: 1920,
+            // The maximum height of resized images:
+            imageMaxHeight: 1080,
+            // Defines the image orientation (1-8) or takes the orientation
+            // value from Exif data if set to true:
+            imageOrientation: false,
+            // Define if resized images should be cropped or only scaled:
+            imageCrop: false,
+            // Disable the resize image functionality by default:
+            disableImageResize: true,
+            // The maximum width of the preview images:
+            previewMaxWidth: 80,
+            // The maximum height of the preview images:
+            previewMaxHeight: 80,
+            // Defines the preview orientation (1-8) or takes the orientation
+            // value from Exif data if set to true:
+            previewOrientation: true,
+            // Create the preview using the Exif data thumbnail:
+            previewThumbnail: true,
+            // Define if preview images should be cropped or only scaled:
+            previewCrop: false,
+            // Define if preview images should be resized as canvas elements:
+            previewCanvas: true
+        },
+
+        processActions: {
+
+            // Loads the image given via data.files and data.index
+            // as img element, if the browser supports the File API.
+            // Accepts the options fileTypes (regular expression)
+            // and maxFileSize (integer) to limit the files to load:
+            loadImage: function (data, options) {
+                if (options.disabled) {
+                    return data;
+                }
+                var that = this,
+                    file = data.files[data.index],
+                    dfd = $.Deferred();
+                if (($.type(options.maxFileSize) === 'number' &&
+                            file.size > options.maxFileSize) ||
+                        (options.fileTypes &&
+                            !options.fileTypes.test(file.type)) ||
+                        !loadImage(
+                            file,
+                            function (img) {
+                                if (img.src) {
+                                    data.img = img;
+                                }
+                                dfd.resolveWith(that, [data]);
+                            },
+                            options
+                        )) {
+                    return data;
+                }
+                return dfd.promise();
+            },
+
+            // Resizes the image given as data.canvas or data.img
+            // and updates data.canvas or data.img with the resized image.
+            // Also stores the resized image as preview property.
+            // Accepts the options maxWidth, maxHeight, minWidth,
+            // minHeight, canvas and crop:
+            resizeImage: function (data, options) {
+                if (options.disabled || !(data.canvas || data.img)) {
+                    return data;
+                }
+                options = $.extend({canvas: true}, options);
+                var that = this,
+                    dfd = $.Deferred(),
+                    img = (options.canvas && data.canvas) || data.img,
+                    resolve = function (newImg) {
+                        if (newImg && (newImg.width !== img.width ||
+                                newImg.height !== img.height ||
+                                options.forceResize)) {
+                            data[newImg.getContext ? 'canvas' : 'img'] = newImg;
+                        }
+                        data.preview = newImg;
+                        dfd.resolveWith(that, [data]);
+                    },
+                    thumbnail;
+                if (data.exif) {
+                    if (options.orientation === true) {
+                        options.orientation = data.exif.get('Orientation');
+                    }
+                    if (options.thumbnail) {
+                        thumbnail = data.exif.get('Thumbnail');
+                        if (thumbnail) {
+                            loadImage(thumbnail, resolve, options);
+                            return dfd.promise();
+                        }
+                    }
+                    // Prevent orienting the same image twice:
+                    if (data.orientation) {
+                        delete options.orientation;
+                    } else {
+                        data.orientation = options.orientation;
+                    }
+                }
+                if (img) {
+                    resolve(loadImage.scale(img, options));
+                    return dfd.promise();
+                }
+                return data;
+            },
+
+            // Saves the processed image given as data.canvas
+            // inplace at data.index of data.files:
+            saveImage: function (data, options) {
+                if (!data.canvas || options.disabled) {
+                    return data;
+                }
+                var that = this,
+                    file = data.files[data.index],
+                    dfd = $.Deferred();
+                if (data.canvas.toBlob) {
+                    data.canvas.toBlob(
+                        function (blob) {
+                            if (!blob.name) {
+                                if (file.type === blob.type) {
+                                    blob.name = file.name;
+                                } else if (file.name) {
+                                    blob.name = file.name.replace(
+                                        /\.\w+$/,
+                                        '.' + blob.type.substr(6)
+                                    );
+                                }
+                            }
+                            // Don't restore invalid meta data:
+                            if (file.type !== blob.type) {
+                                delete data.imageHead;
+                            }
+                            // Store the created blob at the position
+                            // of the original file in the files list:
+                            data.files[data.index] = blob;
+                            dfd.resolveWith(that, [data]);
+                        },
+                        options.type || file.type,
+                        options.quality
+                    );
+                } else {
+                    return data;
+                }
+                return dfd.promise();
+            },
+
+            loadImageMetaData: function (data, options) {
+                if (options.disabled) {
+                    return data;
+                }
+                var that = this,
+                    dfd = $.Deferred();
+                loadImage.parseMetaData(data.files[data.index], function (result) {
+                    $.extend(data, result);
+                    dfd.resolveWith(that, [data]);
+                }, options);
+                return dfd.promise();
+            },
+
+            saveImageMetaData: function (data, options) {
+                if (!(data.imageHead && data.canvas &&
+                        data.canvas.toBlob && !options.disabled)) {
+                    return data;
+                }
+                var file = data.files[data.index],
+                    blob = new Blob([
+                        data.imageHead,
+                        // Resized images always have a head size of 20 bytes,
+                        // including the JPEG marker and a minimal JFIF header:
+                        this._blobSlice.call(file, 20)
+                    ], {type: file.type});
+                blob.name = file.name;
+                data.files[data.index] = blob;
+                return data;
+            },
+
+            // Sets the resized version of the image as a property of the
+            // file object, must be called after "saveImage":
+            setImage: function (data, options) {
+                if (data.preview && !options.disabled) {
+                    data.files[data.index][options.name || 'preview'] = data.preview;
+                }
+                return data;
+            },
+
+            deleteImageReferences: function (data, options) {
+                if (!options.disabled) {
+                    delete data.img;
+                    delete data.canvas;
+                    delete data.preview;
+                    delete data.imageHead;
+                }
+                return data;
+            }
+
+        }
+
+    });
+
+}));

+ 161 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-jquery-ui.js

@@ -0,0 +1,161 @@
+/*
+ * jQuery File Upload jQuery UI Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            './jquery.fileupload-ui'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('./jquery.fileupload-ui')
+        );
+    } else {
+        // Browser globals:
+        factory(window.jQuery);
+    }
+}(function ($) {
+    'use strict';
+
+    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
+
+        options: {
+            processdone: function (e, data) {
+                data.context.find('.start').button('enable');
+            },
+            progress: function (e, data) {
+                if (data.context) {
+                    data.context.find('.progress').progressbar(
+                        'option',
+                        'value',
+                        parseInt(data.loaded / data.total * 100, 10)
+                    );
+                }
+            },
+            progressall: function (e, data) {
+                var $this = $(this);
+                $this.find('.fileupload-progress')
+                    .find('.progress').progressbar(
+                        'option',
+                        'value',
+                        parseInt(data.loaded / data.total * 100, 10)
+                    ).end()
+                    .find('.progress-extended').each(function () {
+                        $(this).html(
+                            ($this.data('blueimp-fileupload') ||
+                                    $this.data('fileupload'))
+                                ._renderExtendedProgress(data)
+                        );
+                    });
+            }
+        },
+
+        _renderUpload: function (func, files) {
+            var node = this._super(func, files),
+                showIconText = $(window).width() > 480;
+            node.find('.progress').empty().progressbar();
+            node.find('.start').button({
+                icons: {primary: 'ui-icon-circle-arrow-e'},
+                text: showIconText
+            });
+            node.find('.cancel').button({
+                icons: {primary: 'ui-icon-cancel'},
+                text: showIconText
+            });
+            if (node.hasClass('fade')) {
+                node.hide();
+            }
+            return node;
+        },
+
+        _renderDownload: function (func, files) {
+            var node = this._super(func, files),
+                showIconText = $(window).width() > 480;
+            node.find('.delete').button({
+                icons: {primary: 'ui-icon-trash'},
+                text: showIconText
+            });
+            if (node.hasClass('fade')) {
+                node.hide();
+            }
+            return node;
+        },
+
+        _startHandler: function (e) {
+            $(e.currentTarget).button('disable');
+            this._super(e);
+        },
+
+        _transition: function (node) {
+            var deferred = $.Deferred();
+            if (node.hasClass('fade')) {
+                node.fadeToggle(
+                    this.options.transitionDuration,
+                    this.options.transitionEasing,
+                    function () {
+                        deferred.resolveWith(node);
+                    }
+                );
+            } else {
+                deferred.resolveWith(node);
+            }
+            return deferred;
+        },
+
+        _create: function () {
+            this._super();
+            this.element
+                .find('.fileupload-buttonbar')
+                .find('.fileinput-button').each(function () {
+                    var input = $(this).find('input:file').detach();
+                    $(this)
+                        .button({icons: {primary: 'ui-icon-plusthick'}})
+                        .append(input);
+                })
+                .end().find('.start')
+                .button({icons: {primary: 'ui-icon-circle-arrow-e'}})
+                .end().find('.cancel')
+                .button({icons: {primary: 'ui-icon-cancel'}})
+                .end().find('.delete')
+                .button({icons: {primary: 'ui-icon-trash'}})
+                .end().find('.progress').progressbar();
+        },
+
+        _destroy: function () {
+            this.element
+                .find('.fileupload-buttonbar')
+                .find('.fileinput-button').each(function () {
+                    var input = $(this).find('input:file').detach();
+                    $(this)
+                        .button('destroy')
+                        .append(input);
+                })
+                .end().find('.start')
+                .button('destroy')
+                .end().find('.cancel')
+                .button('destroy')
+                .end().find('.delete')
+                .button('destroy')
+                .end().find('.progress').progressbar('destroy');
+            this._super();
+        }
+
+    });
+
+}));

+ 178 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-process.js

@@ -0,0 +1,178 @@
+/*
+ * jQuery File Upload Processing Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2012, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            './jquery.fileupload'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('./jquery.fileupload')
+        );
+    } else {
+        // Browser globals:
+        factory(
+            window.jQuery
+        );
+    }
+}(function ($) {
+    'use strict';
+
+    var originalAdd = $.blueimp.fileupload.prototype.options.add;
+
+    // The File Upload Processing plugin extends the fileupload widget
+    // with file processing functionality:
+    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
+
+        options: {
+            // The list of processing actions:
+            processQueue: [
+                /*
+                {
+                    action: 'log',
+                    type: 'debug'
+                }
+                */
+            ],
+            add: function (e, data) {
+                var $this = $(this);
+                data.process(function () {
+                    return $this.fileupload('process', data);
+                });
+                originalAdd.call(this, e, data);
+            }
+        },
+
+        processActions: {
+            /*
+            log: function (data, options) {
+                console[options.type](
+                    'Processing "' + data.files[data.index].name + '"'
+                );
+            }
+            */
+        },
+
+        _processFile: function (data, originalData) {
+            var that = this,
+                dfd = $.Deferred().resolveWith(that, [data]),
+                chain = dfd.promise();
+            this._trigger('process', null, data);
+            $.each(data.processQueue, function (i, settings) {
+                var func = function (data) {
+                    if (originalData.errorThrown) {
+                        return $.Deferred()
+                                .rejectWith(that, [originalData]).promise();
+                    }
+                    return that.processActions[settings.action].call(
+                        that,
+                        data,
+                        settings
+                    );
+                };
+                chain = chain.then(func, settings.always && func);
+            });
+            chain
+                .done(function () {
+                    that._trigger('processdone', null, data);
+                    that._trigger('processalways', null, data);
+                })
+                .fail(function () {
+                    that._trigger('processfail', null, data);
+                    that._trigger('processalways', null, data);
+                });
+            return chain;
+        },
+
+        // Replaces the settings of each processQueue item that
+        // are strings starting with an "@", using the remaining
+        // substring as key for the option map,
+        // e.g. "@autoUpload" is replaced with options.autoUpload:
+        _transformProcessQueue: function (options) {
+            var processQueue = [];
+            $.each(options.processQueue, function () {
+                var settings = {},
+                    action = this.action,
+                    prefix = this.prefix === true ? action : this.prefix;
+                $.each(this, function (key, value) {
+                    if ($.type(value) === 'string' &&
+                            value.charAt(0) === '@') {
+                        settings[key] = options[
+                            value.slice(1) || (prefix ? prefix +
+                                key.charAt(0).toUpperCase() + key.slice(1) : key)
+                        ];
+                    } else {
+                        settings[key] = value;
+                    }
+
+                });
+                processQueue.push(settings);
+            });
+            options.processQueue = processQueue;
+        },
+
+        // Returns the number of files currently in the processsing queue:
+        processing: function () {
+            return this._processing;
+        },
+
+        // Processes the files given as files property of the data parameter,
+        // returns a Promise object that allows to bind callbacks:
+        process: function (data) {
+            var that = this,
+                options = $.extend({}, this.options, data);
+            if (options.processQueue && options.processQueue.length) {
+                this._transformProcessQueue(options);
+                if (this._processing === 0) {
+                    this._trigger('processstart');
+                }
+                $.each(data.files, function (index) {
+                    var opts = index ? $.extend({}, options) : options,
+                        func = function () {
+                            if (data.errorThrown) {
+                                return $.Deferred()
+                                        .rejectWith(that, [data]).promise();
+                            }
+                            return that._processFile(opts, data);
+                        };
+                    opts.index = index;
+                    that._processing += 1;
+                    that._processingQueue = that._processingQueue.then(func, func)
+                        .always(function () {
+                            that._processing -= 1;
+                            if (that._processing === 0) {
+                                that._trigger('processstop');
+                            }
+                        });
+                });
+            }
+            return this._processingQueue;
+        },
+
+        _create: function () {
+            this._super();
+            this._processing = 0;
+            this._processingQueue = $.Deferred().resolveWith(this)
+                .promise();
+        }
+
+    });
+
+}));

+ 714 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-ui.js

@@ -0,0 +1,714 @@
+/*
+ * jQuery File Upload User Interface Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            'blueimp-tmpl',
+            './jquery.fileupload-image',
+            './jquery.fileupload-audio',
+            './jquery.fileupload-video',
+            './jquery.fileupload-validate'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('blueimp-tmpl'),
+            require('./jquery.fileupload-image'),
+            require('./jquery.fileupload-audio'),
+            require('./jquery.fileupload-video'),
+            require('./jquery.fileupload-validate')
+        );
+    } else {
+        // Browser globals:
+        factory(
+            window.jQuery,
+            window.tmpl
+        );
+    }
+}(function ($, tmpl) {
+    'use strict';
+
+    $.blueimp.fileupload.prototype._specialOptions.push(
+        'filesContainer',
+        'uploadTemplateId',
+        'downloadTemplateId'
+    );
+
+    // The UI version extends the file upload widget
+    // and adds complete user interface interaction:
+    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
+
+        options: {
+            // By default, files added to the widget are uploaded as soon
+            // as the user clicks on the start buttons. To enable automatic
+            // uploads, set the following option to true:
+            autoUpload: false,
+            // The ID of the upload template:
+            uploadTemplateId: 'template-upload',
+            // The ID of the download template:
+            downloadTemplateId: 'template-download',
+            // The container for the list of files. If undefined, it is set to
+            // an element with class "files" inside of the widget element:
+            filesContainer: undefined,
+            // By default, files are appended to the files container.
+            // Set the following option to true, to prepend files instead:
+            prependFiles: false,
+            // The expected data type of the upload response, sets the dataType
+            // option of the $.ajax upload requests:
+            dataType: 'json',
+
+            // Error and info messages:
+            messages: {
+                unknownError: 'Unknown error'
+            },
+
+            // Function returning the current number of files,
+            // used by the maxNumberOfFiles validation:
+            getNumberOfFiles: function () {
+                return this.filesContainer.children()
+                    .not('.processing').length;
+            },
+
+            // Callback to retrieve the list of files from the server response:
+            getFilesFromResponse: function (data) {
+                if (data.result && $.isArray(data.result.files)) {
+                    return data.result.files;
+                }
+                return [];
+            },
+
+            // The add callback is invoked as soon as files are added to the fileupload
+            // widget (via file input selection, drag & drop or add API call).
+            // See the basic file upload widget for more information:
+            add: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var $this = $(this),
+                    that = $this.data('blueimp-fileupload') ||
+                        $this.data('fileupload'),
+                    options = that.options;
+                data.context = that._renderUpload(data.files)
+                    .data('data', data)
+                    .addClass('processing');
+                options.filesContainer[
+                    options.prependFiles ? 'prepend' : 'append'
+                ](data.context);
+                that._forceReflow(data.context);
+                that._transition(data.context);
+                data.process(function () {
+                    return $this.fileupload('process', data);
+                }).always(function () {
+                    data.context.each(function (index) {
+                        $(this).find('.size').text(
+                            that._formatFileSize(data.files[index].size)
+                        );
+                    }).removeClass('processing');
+                    that._renderPreviews(data);
+                }).done(function () {
+                    data.context.find('.start').prop('disabled', false);
+                    if ((that._trigger('added', e, data) !== false) &&
+                            (options.autoUpload || data.autoUpload) &&
+                            data.autoUpload !== false) {
+                        data.submit();
+                    }
+                }).fail(function () {
+                    if (data.files.error) {
+                        data.context.each(function (index) {
+                            var error = data.files[index].error;
+                            if (error) {
+                                $(this).find('.error').text(error);
+                            }
+                        });
+                    }
+                });
+            },
+            // Callback for the start of each file upload request:
+            send: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var that = $(this).data('blueimp-fileupload') ||
+                        $(this).data('fileupload');
+                if (data.context && data.dataType &&
+                        data.dataType.substr(0, 6) === 'iframe') {
+                    // Iframe Transport does not support progress events.
+                    // In lack of an indeterminate progress bar, we set
+                    // the progress to 100%, showing the full animated bar:
+                    data.context
+                        .find('.progress').addClass(
+                            !$.support.transition && 'progress-animated'
+                        )
+                        .attr('aria-valuenow', 100)
+                        .children().first().css(
+                            'width',
+                            '100%'
+                        );
+                }
+                return that._trigger('sent', e, data);
+            },
+            // Callback for successful uploads:
+            done: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var that = $(this).data('blueimp-fileupload') ||
+                        $(this).data('fileupload'),
+                    getFilesFromResponse = data.getFilesFromResponse ||
+                        that.options.getFilesFromResponse,
+                    files = getFilesFromResponse(data),
+                    template,
+                    deferred;
+                if (data.context) {
+                    data.context.each(function (index) {
+                        var file = files[index] ||
+                                {error: 'Empty file upload result'};
+                        deferred = that._addFinishedDeferreds();
+                        that._transition($(this)).done(
+                            function () {
+                                var node = $(this);
+                                template = that._renderDownload([file])
+                                    .replaceAll(node);
+                                that._forceReflow(template);
+                                that._transition(template).done(
+                                    function () {
+                                        data.context = $(this);
+                                        that._trigger('completed', e, data);
+                                        that._trigger('finished', e, data);
+                                        deferred.resolve();
+                                    }
+                                );
+                            }
+                        );
+                    });
+                } else {
+                    template = that._renderDownload(files)[
+                        that.options.prependFiles ? 'prependTo' : 'appendTo'
+                    ](that.options.filesContainer);
+                    that._forceReflow(template);
+                    deferred = that._addFinishedDeferreds();
+                    that._transition(template).done(
+                        function () {
+                            data.context = $(this);
+                            that._trigger('completed', e, data);
+                            that._trigger('finished', e, data);
+                            deferred.resolve();
+                        }
+                    );
+                }
+            },
+            // Callback for failed (abort or error) uploads:
+            fail: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var that = $(this).data('blueimp-fileupload') ||
+                        $(this).data('fileupload'),
+                    template,
+                    deferred;
+                if (data.context) {
+                    data.context.each(function (index) {
+                        if (data.errorThrown !== 'abort') {
+                            var file = data.files[index];
+                            file.error = file.error || data.errorThrown ||
+                                data.i18n('unknownError');
+                            deferred = that._addFinishedDeferreds();
+                            that._transition($(this)).done(
+                                function () {
+                                    var node = $(this);
+                                    template = that._renderDownload([file])
+                                        .replaceAll(node);
+                                    that._forceReflow(template);
+                                    that._transition(template).done(
+                                        function () {
+                                            data.context = $(this);
+                                            that._trigger('failed', e, data);
+                                            that._trigger('finished', e, data);
+                                            deferred.resolve();
+                                        }
+                                    );
+                                }
+                            );
+                        } else {
+                            deferred = that._addFinishedDeferreds();
+                            that._transition($(this)).done(
+                                function () {
+                                    $(this).remove();
+                                    that._trigger('failed', e, data);
+                                    that._trigger('finished', e, data);
+                                    deferred.resolve();
+                                }
+                            );
+                        }
+                    });
+                } else if (data.errorThrown !== 'abort') {
+                    data.context = that._renderUpload(data.files)[
+                        that.options.prependFiles ? 'prependTo' : 'appendTo'
+                    ](that.options.filesContainer)
+                        .data('data', data);
+                    that._forceReflow(data.context);
+                    deferred = that._addFinishedDeferreds();
+                    that._transition(data.context).done(
+                        function () {
+                            data.context = $(this);
+                            that._trigger('failed', e, data);
+                            that._trigger('finished', e, data);
+                            deferred.resolve();
+                        }
+                    );
+                } else {
+                    that._trigger('failed', e, data);
+                    that._trigger('finished', e, data);
+                    that._addFinishedDeferreds().resolve();
+                }
+            },
+            // Callback for upload progress events:
+            progress: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var progress = Math.floor(data.loaded / data.total * 100);
+                if (data.context) {
+                    data.context.each(function () {
+                        $(this).find('.progress')
+                            .attr('aria-valuenow', progress)
+                            .children().first().css(
+                                'width',
+                                progress + '%'
+                            );
+                    });
+                }
+            },
+            // Callback for global upload progress events:
+            progressall: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var $this = $(this),
+                    progress = Math.floor(data.loaded / data.total * 100),
+                    globalProgressNode = $this.find('.fileupload-progress'),
+                    extendedProgressNode = globalProgressNode
+                        .find('.progress-extended');
+                if (extendedProgressNode.length) {
+                    extendedProgressNode.html(
+                        ($this.data('blueimp-fileupload') || $this.data('fileupload'))
+                            ._renderExtendedProgress(data)
+                    );
+                }
+                globalProgressNode
+                    .find('.progress')
+                    .attr('aria-valuenow', progress)
+                    .children().first().css(
+                        'width',
+                        progress + '%'
+                    );
+            },
+            // Callback for uploads start, equivalent to the global ajaxStart event:
+            start: function (e) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var that = $(this).data('blueimp-fileupload') ||
+                        $(this).data('fileupload');
+                that._resetFinishedDeferreds();
+                that._transition($(this).find('.fileupload-progress')).done(
+                    function () {
+                        that._trigger('started', e);
+                    }
+                );
+            },
+            // Callback for uploads stop, equivalent to the global ajaxStop event:
+            stop: function (e) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var that = $(this).data('blueimp-fileupload') ||
+                        $(this).data('fileupload'),
+                    deferred = that._addFinishedDeferreds();
+                $.when.apply($, that._getFinishedDeferreds())
+                    .done(function () {
+                        that._trigger('stopped', e);
+                    });
+                that._transition($(this).find('.fileupload-progress')).done(
+                    function () {
+                        $(this).find('.progress')
+                            .attr('aria-valuenow', '0')
+                            .children().first().css('width', '0%');
+                        $(this).find('.progress-extended').html('&nbsp;');
+                        deferred.resolve();
+                    }
+                );
+            },
+            processstart: function (e) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                $(this).addClass('fileupload-processing');
+            },
+            processstop: function (e) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                $(this).removeClass('fileupload-processing');
+            },
+            // Callback for file deletion:
+            destroy: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                var that = $(this).data('blueimp-fileupload') ||
+                        $(this).data('fileupload'),
+                    removeNode = function () {
+                        that._transition(data.context).done(
+                            function () {
+                                $(this).remove();
+                                that._trigger('destroyed', e, data);
+                            }
+                        );
+                    };
+                if (data.url) {
+                    data.dataType = data.dataType || that.options.dataType;
+                    $.ajax(data).done(removeNode).fail(function () {
+                        that._trigger('destroyfailed', e, data);
+                    });
+                } else {
+                    removeNode();
+                }
+            }
+        },
+
+        _resetFinishedDeferreds: function () {
+            this._finishedUploads = [];
+        },
+
+        _addFinishedDeferreds: function (deferred) {
+            if (!deferred) {
+                deferred = $.Deferred();
+            }
+            this._finishedUploads.push(deferred);
+            return deferred;
+        },
+
+        _getFinishedDeferreds: function () {
+            return this._finishedUploads;
+        },
+
+        // Link handler, that allows to download files
+        // by drag & drop of the links to the desktop:
+        _enableDragToDesktop: function () {
+            var link = $(this),
+                url = link.prop('href'),
+                name = link.prop('download'),
+                type = 'application/octet-stream';
+            link.bind('dragstart', function (e) {
+                try {
+                    e.originalEvent.dataTransfer.setData(
+                        'DownloadURL',
+                        [type, name, url].join(':')
+                    );
+                } catch (ignore) {}
+            });
+        },
+
+        _formatFileSize: function (bytes) {
+            if (typeof bytes !== 'number') {
+                return '';
+            }
+            if (bytes >= 1000000000) {
+                return (bytes / 1000000000).toFixed(2) + ' GB';
+            }
+            if (bytes >= 1000000) {
+                return (bytes / 1000000).toFixed(2) + ' MB';
+            }
+            return (bytes / 1000).toFixed(2) + ' KB';
+        },
+
+        _formatBitrate: function (bits) {
+            if (typeof bits !== 'number') {
+                return '';
+            }
+            if (bits >= 1000000000) {
+                return (bits / 1000000000).toFixed(2) + ' Gbit/s';
+            }
+            if (bits >= 1000000) {
+                return (bits / 1000000).toFixed(2) + ' Mbit/s';
+            }
+            if (bits >= 1000) {
+                return (bits / 1000).toFixed(2) + ' kbit/s';
+            }
+            return bits.toFixed(2) + ' bit/s';
+        },
+
+        _formatTime: function (seconds) {
+            var date = new Date(seconds * 1000),
+                days = Math.floor(seconds / 86400);
+            days = days ? days + 'd ' : '';
+            return days +
+                ('0' + date.getUTCHours()).slice(-2) + ':' +
+                ('0' + date.getUTCMinutes()).slice(-2) + ':' +
+                ('0' + date.getUTCSeconds()).slice(-2);
+        },
+
+        _formatPercentage: function (floatValue) {
+            return (floatValue * 100).toFixed(2) + ' %';
+        },
+
+        _renderExtendedProgress: function (data) {
+            return this._formatBitrate(data.bitrate) + ' | ' +
+                this._formatTime(
+                    (data.total - data.loaded) * 8 / data.bitrate
+                ) + ' | ' +
+                this._formatPercentage(
+                    data.loaded / data.total
+                ) + ' | ' +
+                this._formatFileSize(data.loaded) + ' / ' +
+                this._formatFileSize(data.total);
+        },
+
+        _renderTemplate: function (func, files) {
+            if (!func) {
+                return $();
+            }
+            var result = func({
+                files: files,
+                formatFileSize: this._formatFileSize,
+                options: this.options
+            });
+            if (result instanceof $) {
+                return result;
+            }
+            return $(this.options.templatesContainer).html(result).children();
+        },
+
+        _renderPreviews: function (data) {
+            data.context.find('.preview').each(function (index, elm) {
+                $(elm).append(data.files[index].preview);
+            });
+        },
+
+        _renderUpload: function (files) {
+            return this._renderTemplate(
+                this.options.uploadTemplate,
+                files
+            );
+        },
+
+        _renderDownload: function (files) {
+            return this._renderTemplate(
+                this.options.downloadTemplate,
+                files
+            ).find('a[download]').each(this._enableDragToDesktop).end();
+        },
+
+        _startHandler: function (e) {
+            e.preventDefault();
+            var button = $(e.currentTarget),
+                template = button.closest('.template-upload'),
+                data = template.data('data');
+            button.prop('disabled', true);
+            if (data && data.submit) {
+                data.submit();
+            }
+        },
+
+        _cancelHandler: function (e) {
+            e.preventDefault();
+            var template = $(e.currentTarget)
+                    .closest('.template-upload,.template-download'),
+                data = template.data('data') || {};
+            data.context = data.context || template;
+            if (data.abort) {
+                data.abort();
+            } else {
+                data.errorThrown = 'abort';
+                this._trigger('fail', e, data);
+            }
+        },
+
+        _deleteHandler: function (e) {
+            e.preventDefault();
+            var button = $(e.currentTarget);
+            this._trigger('destroy', e, $.extend({
+                context: button.closest('.template-download'),
+                type: 'DELETE'
+            }, button.data()));
+        },
+
+        _forceReflow: function (node) {
+            return $.support.transition && node.length &&
+                node[0].offsetWidth;
+        },
+
+        _transition: function (node) {
+            var dfd = $.Deferred();
+            if ($.support.transition && node.hasClass('fade') && node.is(':visible')) {
+                node.bind(
+                    $.support.transition.end,
+                    function (e) {
+                        // Make sure we don't respond to other transitions events
+                        // in the container element, e.g. from button elements:
+                        if (e.target === node[0]) {
+                            node.unbind($.support.transition.end);
+                            dfd.resolveWith(node);
+                        }
+                    }
+                ).toggleClass('in');
+            } else {
+                node.toggleClass('in');
+                dfd.resolveWith(node);
+            }
+            return dfd;
+        },
+
+        _initButtonBarEventHandlers: function () {
+            var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
+                filesList = this.options.filesContainer;
+            this._on(fileUploadButtonBar.find('.start'), {
+                click: function (e) {
+                    e.preventDefault();
+                    filesList.find('.start').click();
+                }
+            });
+            this._on(fileUploadButtonBar.find('.cancel'), {
+                click: function (e) {
+                    e.preventDefault();
+                    filesList.find('.cancel').click();
+                }
+            });
+            this._on(fileUploadButtonBar.find('.delete'), {
+                click: function (e) {
+                    e.preventDefault();
+                    filesList.find('.toggle:checked')
+                        .closest('.template-download')
+                        .find('.delete').click();
+                    fileUploadButtonBar.find('.toggle')
+                        .prop('checked', false);
+                }
+            });
+            this._on(fileUploadButtonBar.find('.toggle'), {
+                change: function (e) {
+                    filesList.find('.toggle').prop(
+                        'checked',
+                        $(e.currentTarget).is(':checked')
+                    );
+                }
+            });
+        },
+
+        _destroyButtonBarEventHandlers: function () {
+            this._off(
+                this.element.find('.fileupload-buttonbar')
+                    .find('.start, .cancel, .delete'),
+                'click'
+            );
+            this._off(
+                this.element.find('.fileupload-buttonbar .toggle'),
+                'change.'
+            );
+        },
+
+        _initEventHandlers: function () {
+            this._super();
+            this._on(this.options.filesContainer, {
+                'click .start': this._startHandler,
+                'click .cancel': this._cancelHandler,
+                'click .delete': this._deleteHandler
+            });
+            this._initButtonBarEventHandlers();
+        },
+
+        _destroyEventHandlers: function () {
+            this._destroyButtonBarEventHandlers();
+            this._off(this.options.filesContainer, 'click');
+            this._super();
+        },
+
+        _enableFileInputButton: function () {
+            this.element.find('.fileinput-button input')
+                .prop('disabled', false)
+                .parent().removeClass('disabled');
+        },
+
+        _disableFileInputButton: function () {
+            this.element.find('.fileinput-button input')
+                .prop('disabled', true)
+                .parent().addClass('disabled');
+        },
+
+        _initTemplates: function () {
+            var options = this.options;
+            options.templatesContainer = this.document[0].createElement(
+                options.filesContainer.prop('nodeName')
+            );
+            if (tmpl) {
+                if (options.uploadTemplateId) {
+                    options.uploadTemplate = tmpl(options.uploadTemplateId);
+                }
+                if (options.downloadTemplateId) {
+                    options.downloadTemplate = tmpl(options.downloadTemplateId);
+                }
+            }
+        },
+
+        _initFilesContainer: function () {
+            var options = this.options;
+            if (options.filesContainer === undefined) {
+                options.filesContainer = this.element.find('.files');
+            } else if (!(options.filesContainer instanceof $)) {
+                options.filesContainer = $(options.filesContainer);
+            }
+        },
+
+        _initSpecialOptions: function () {
+            this._super();
+            this._initFilesContainer();
+            this._initTemplates();
+        },
+
+        _create: function () {
+            this._super();
+            this._resetFinishedDeferreds();
+            if (!$.support.fileInput) {
+                this._disableFileInputButton();
+            }
+        },
+
+        enable: function () {
+            var wasDisabled = false;
+            if (this.options.disabled) {
+                wasDisabled = true;
+            }
+            this._super();
+            if (wasDisabled) {
+                this.element.find('input, button').prop('disabled', false);
+                this._enableFileInputButton();
+            }
+        },
+
+        disable: function () {
+            if (!this.options.disabled) {
+                this.element.find('input, button').prop('disabled', true);
+                this._disableFileInputButton();
+            }
+            this._super();
+        }
+
+    });
+
+}));

+ 125 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-validate.js

@@ -0,0 +1,125 @@
+/*
+ * jQuery File Upload Validation Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* global define, require, window */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            './jquery.fileupload-process'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('./jquery.fileupload-process')
+        );
+    } else {
+        // Browser globals:
+        factory(
+            window.jQuery
+        );
+    }
+}(function ($) {
+    'use strict';
+
+    // Append to the default processQueue:
+    $.blueimp.fileupload.prototype.options.processQueue.push(
+        {
+            action: 'validate',
+            // Always trigger this action,
+            // even if the previous action was rejected:
+            always: true,
+            // Options taken from the global options map:
+            acceptFileTypes: '@',
+            maxFileSize: '@',
+            minFileSize: '@',
+            maxNumberOfFiles: '@',
+            disabled: '@disableValidation'
+        }
+    );
+
+    // The File Upload Validation plugin extends the fileupload widget
+    // with file validation functionality:
+    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
+
+        options: {
+            /*
+            // The regular expression for allowed file types, matches
+            // against either file type or file name:
+            acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
+            // The maximum allowed file size in bytes:
+            maxFileSize: 10000000, // 10 MB
+            // The minimum allowed file size in bytes:
+            minFileSize: undefined, // No minimal file size
+            // The limit of files to be uploaded:
+            maxNumberOfFiles: 10,
+            */
+
+            // Function returning the current number of files,
+            // has to be overriden for maxNumberOfFiles validation:
+            getNumberOfFiles: $.noop,
+
+            // Error and info messages:
+            messages: {
+                maxNumberOfFiles: 'Maximum number of files exceeded',
+                acceptFileTypes: 'File type not allowed',
+                maxFileSize: 'File is too large',
+                minFileSize: 'File is too small'
+            }
+        },
+
+        processActions: {
+
+            validate: function (data, options) {
+                if (options.disabled) {
+                    return data;
+                }
+                var dfd = $.Deferred(),
+                    settings = this.options,
+                    file = data.files[data.index],
+                    fileSize;
+                if (options.minFileSize || options.maxFileSize) {
+                    fileSize = file.size;
+                }
+                if ($.type(options.maxNumberOfFiles) === 'number' &&
+                        (settings.getNumberOfFiles() || 0) + data.files.length >
+                            options.maxNumberOfFiles) {
+                    file.error = settings.i18n('maxNumberOfFiles');
+                } else if (options.acceptFileTypes &&
+                        !(options.acceptFileTypes.test(file.type) ||
+                        options.acceptFileTypes.test(file.name))) {
+                    file.error = settings.i18n('acceptFileTypes');
+                } else if (fileSize > options.maxFileSize) {
+                    file.error = settings.i18n('maxFileSize');
+                } else if ($.type(fileSize) === 'number' &&
+                        fileSize < options.minFileSize) {
+                    file.error = settings.i18n('minFileSize');
+                } else {
+                    delete file.error;
+                }
+                if (file.error || data.files.error) {
+                    data.files.error = true;
+                    dfd.rejectWith(this, [data]);
+                } else {
+                    dfd.resolveWith(this, [data]);
+                }
+                return dfd.promise();
+            }
+
+        }
+
+    });
+
+}));

+ 113 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload-video.js

@@ -0,0 +1,113 @@
+/*
+ * jQuery File Upload Video Preview Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2013, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window, document */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            'load-image',
+            './jquery.fileupload-process'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('blueimp-load-image/js/load-image'),
+            require('./jquery.fileupload-process')
+        );
+    } else {
+        // Browser globals:
+        factory(
+            window.jQuery,
+            window.loadImage
+        );
+    }
+}(function ($, loadImage) {
+    'use strict';
+
+    // Prepend to the default processQueue:
+    $.blueimp.fileupload.prototype.options.processQueue.unshift(
+        {
+            action: 'loadVideo',
+            // Use the action as prefix for the "@" options:
+            prefix: true,
+            fileTypes: '@',
+            maxFileSize: '@',
+            disabled: '@disableVideoPreview'
+        },
+        {
+            action: 'setVideo',
+            name: '@videoPreviewName',
+            disabled: '@disableVideoPreview'
+        }
+    );
+
+    // The File Upload Video Preview plugin extends the fileupload widget
+    // with video preview functionality:
+    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
+
+        options: {
+            // The regular expression for the types of video files to load,
+            // matched against the file type:
+            loadVideoFileTypes: /^video\/.*$/
+        },
+
+        _videoElement: document.createElement('video'),
+
+        processActions: {
+
+            // Loads the video file given via data.files and data.index
+            // as video element if the browser supports playing it.
+            // Accepts the options fileTypes (regular expression)
+            // and maxFileSize (integer) to limit the files to load:
+            loadVideo: function (data, options) {
+                if (options.disabled) {
+                    return data;
+                }
+                var file = data.files[data.index],
+                    url,
+                    video;
+                if (this._videoElement.canPlayType &&
+                        this._videoElement.canPlayType(file.type) &&
+                        ($.type(options.maxFileSize) !== 'number' ||
+                            file.size <= options.maxFileSize) &&
+                        (!options.fileTypes ||
+                            options.fileTypes.test(file.type))) {
+                    url = loadImage.createObjectURL(file);
+                    if (url) {
+                        video = this._videoElement.cloneNode(false);
+                        video.src = url;
+                        video.controls = true;
+                        data.video = video;
+                        return data;
+                    }
+                }
+                return data;
+            },
+
+            // Sets the video element as a property of the file object:
+            setVideo: function (data, options) {
+                if (data.video && !options.disabled) {
+                    data.files[data.index][options.name || 'preview'] = data.video;
+                }
+                return data;
+            }
+
+        }
+
+    });
+
+}));

+ 1486 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.fileupload.js

@@ -0,0 +1,1486 @@
+/*
+ * jQuery File Upload Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window, document, location, Blob, FormData */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define([
+            'jquery',
+            'jquery-ui/ui/widget'
+        ], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(
+            require('jquery'),
+            require('./vendor/jquery.ui.widget')
+        );
+    } else {
+        // Browser globals:
+        factory(window.jQuery);
+    }
+}(function ($) {
+    'use strict';
+
+    // Detect file input support, based on
+    // http://viljamis.com/blog/2012/file-upload-support-on-mobile/
+    $.support.fileInput = !(new RegExp(
+        // Handle devices which give false positives for the feature detection:
+        '(Android (1\\.[0156]|2\\.[01]))' +
+            '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
+            '|(w(eb)?OSBrowser)|(webOS)' +
+            '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
+    ).test(window.navigator.userAgent) ||
+        // Feature detection for all other devices:
+        $('<input type="file">').prop('disabled'));
+
+    // The FileReader API is not actually used, but works as feature detection,
+    // as some Safari versions (5?) support XHR file uploads via the FormData API,
+    // but not non-multipart XHR file uploads.
+    // window.XMLHttpRequestUpload is not available on IE10, so we check for
+    // window.ProgressEvent instead to detect XHR2 file upload capability:
+    $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);
+    $.support.xhrFormDataFileUpload = !!window.FormData;
+
+    // Detect support for Blob slicing (required for chunked uploads):
+    $.support.blobSlice = window.Blob && (Blob.prototype.slice ||
+        Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
+
+    // Helper function to create drag handlers for dragover/dragenter/dragleave:
+    function getDragHandler(type) {
+        var isDragOver = type === 'dragover';
+        return function (e) {
+            e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
+            var dataTransfer = e.dataTransfer;
+            if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
+                    this._trigger(
+                        type,
+                        $.Event(type, {delegatedEvent: e})
+                    ) !== false) {
+                e.preventDefault();
+                if (isDragOver) {
+                    dataTransfer.dropEffect = 'copy';
+                }
+            }
+        };
+    }
+
+    // The fileupload widget listens for change events on file input fields defined
+    // via fileInput setting and paste or drop events of the given dropZone.
+    // In addition to the default jQuery Widget methods, the fileupload widget
+    // exposes the "add" and "send" methods, to add or directly send files using
+    // the fileupload API.
+    // By default, files added via file input selection, paste, drag & drop or
+    // "add" method are uploaded immediately, but it is possible to override
+    // the "add" callback option to queue file uploads.
+    $.widget('blueimp.fileupload', {
+
+        options: {
+            // The drop target element(s), by the default the complete document.
+            // Set to null to disable drag & drop support:
+            dropZone: $(document),
+            // The paste target element(s), by the default undefined.
+            // Set to a DOM node or jQuery object to enable file pasting:
+            pasteZone: undefined,
+            // The file input field(s), that are listened to for change events.
+            // If undefined, it is set to the file input fields inside
+            // of the widget element on plugin initialization.
+            // Set to null to disable the change listener.
+            fileInput: undefined,
+            // By default, the file input field is replaced with a clone after
+            // each input field change event. This is required for iframe transport
+            // queues and allows change events to be fired for the same file
+            // selection, but can be disabled by setting the following option to false:
+            replaceFileInput: true,
+            // The parameter name for the file form data (the request argument name).
+            // If undefined or empty, the name property of the file input field is
+            // used, or "files[]" if the file input name property is also empty,
+            // can be a string or an array of strings:
+            paramName: undefined,
+            // By default, each file of a selection is uploaded using an individual
+            // request for XHR type uploads. Set to false to upload file
+            // selections in one request each:
+            singleFileUploads: true,
+            // To limit the number of files uploaded with one XHR request,
+            // set the following option to an integer greater than 0:
+            limitMultiFileUploads: undefined,
+            // The following option limits the number of files uploaded with one
+            // XHR request to keep the request size under or equal to the defined
+            // limit in bytes:
+            limitMultiFileUploadSize: undefined,
+            // Multipart file uploads add a number of bytes to each uploaded file,
+            // therefore the following option adds an overhead for each file used
+            // in the limitMultiFileUploadSize configuration:
+            limitMultiFileUploadSizeOverhead: 512,
+            // Set the following option to true to issue all file upload requests
+            // in a sequential order:
+            sequentialUploads: false,
+            // To limit the number of concurrent uploads,
+            // set the following option to an integer greater than 0:
+            limitConcurrentUploads: undefined,
+            // Set the following option to true to force iframe transport uploads:
+            forceIframeTransport: false,
+            // Set the following option to the location of a redirect url on the
+            // origin server, for cross-domain iframe transport uploads:
+            redirect: undefined,
+            // The parameter name for the redirect url, sent as part of the form
+            // data and set to 'redirect' if this option is empty:
+            redirectParamName: undefined,
+            // Set the following option to the location of a postMessage window,
+            // to enable postMessage transport uploads:
+            postMessage: undefined,
+            // By default, XHR file uploads are sent as multipart/form-data.
+            // The iframe transport is always using multipart/form-data.
+            // Set to false to enable non-multipart XHR uploads:
+            multipart: true,
+            // To upload large files in smaller chunks, set the following option
+            // to a preferred maximum chunk size. If set to 0, null or undefined,
+            // or the browser does not support the required Blob API, files will
+            // be uploaded as a whole.
+            maxChunkSize: undefined,
+            // When a non-multipart upload or a chunked multipart upload has been
+            // aborted, this option can be used to resume the upload by setting
+            // it to the size of the already uploaded bytes. This option is most
+            // useful when modifying the options object inside of the "add" or
+            // "send" callbacks, as the options are cloned for each file upload.
+            uploadedBytes: undefined,
+            // By default, failed (abort or error) file uploads are removed from the
+            // global progress calculation. Set the following option to false to
+            // prevent recalculating the global progress data:
+            recalculateProgress: true,
+            // Interval in milliseconds to calculate and trigger progress events:
+            progressInterval: 100,
+            // Interval in milliseconds to calculate progress bitrate:
+            bitrateInterval: 500,
+            // By default, uploads are started automatically when adding files:
+            autoUpload: true,
+
+            // Error and info messages:
+            messages: {
+                uploadedBytes: 'Uploaded bytes exceed file size'
+            },
+
+            // Translation function, gets the message key to be translated
+            // and an object with context specific data as arguments:
+            i18n: function (message, context) {
+                message = this.messages[message] || message.toString();
+                if (context) {
+                    $.each(context, function (key, value) {
+                        message = message.replace('{' + key + '}', value);
+                    });
+                }
+                return message;
+            },
+
+            // Additional form data to be sent along with the file uploads can be set
+            // using this option, which accepts an array of objects with name and
+            // value properties, a function returning such an array, a FormData
+            // object (for XHR file uploads), or a simple object.
+            // The form of the first fileInput is given as parameter to the function:
+            formData: function (form) {
+                return form.serializeArray();
+            },
+
+            // The add callback is invoked as soon as files are added to the fileupload
+            // widget (via file input selection, drag & drop, paste or add API call).
+            // If the singleFileUploads option is enabled, this callback will be
+            // called once for each file in the selection for XHR file uploads, else
+            // once for each file selection.
+            //
+            // The upload starts when the submit method is invoked on the data parameter.
+            // The data object contains a files property holding the added files
+            // and allows you to override plugin options as well as define ajax settings.
+            //
+            // Listeners for this callback can also be bound the following way:
+            // .bind('fileuploadadd', func);
+            //
+            // data.submit() returns a Promise object and allows to attach additional
+            // handlers using jQuery's Deferred callbacks:
+            // data.submit().done(func).fail(func).always(func);
+            add: function (e, data) {
+                if (e.isDefaultPrevented()) {
+                    return false;
+                }
+                if (data.autoUpload || (data.autoUpload !== false &&
+                        $(this).fileupload('option', 'autoUpload'))) {
+                    data.process().done(function () {
+                        data.submit();
+                    });
+                }
+            },
+
+            // Other callbacks:
+
+            // Callback for the submit event of each file upload:
+            // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
+
+            // Callback for the start of each file upload request:
+            // send: function (e, data) {}, // .bind('fileuploadsend', func);
+
+            // Callback for successful uploads:
+            // done: function (e, data) {}, // .bind('fileuploaddone', func);
+
+            // Callback for failed (abort or error) uploads:
+            // fail: function (e, data) {}, // .bind('fileuploadfail', func);
+
+            // Callback for completed (success, abort or error) requests:
+            // always: function (e, data) {}, // .bind('fileuploadalways', func);
+
+            // Callback for upload progress events:
+            // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
+
+            // Callback for global upload progress events:
+            // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
+
+            // Callback for uploads start, equivalent to the global ajaxStart event:
+            // start: function (e) {}, // .bind('fileuploadstart', func);
+
+            // Callback for uploads stop, equivalent to the global ajaxStop event:
+            // stop: function (e) {}, // .bind('fileuploadstop', func);
+
+            // Callback for change events of the fileInput(s):
+            // change: function (e, data) {}, // .bind('fileuploadchange', func);
+
+            // Callback for paste events to the pasteZone(s):
+            // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
+
+            // Callback for drop events of the dropZone(s):
+            // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
+
+            // Callback for dragover events of the dropZone(s):
+            // dragover: function (e) {}, // .bind('fileuploaddragover', func);
+
+            // Callback for the start of each chunk upload request:
+            // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
+
+            // Callback for successful chunk uploads:
+            // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
+
+            // Callback for failed (abort or error) chunk uploads:
+            // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
+
+            // Callback for completed (success, abort or error) chunk upload requests:
+            // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
+
+            // The plugin options are used as settings object for the ajax calls.
+            // The following are jQuery ajax settings required for the file uploads:
+            processData: false,
+            contentType: false,
+            cache: false,
+            timeout: 0
+        },
+
+        // A list of options that require reinitializing event listeners and/or
+        // special initialization code:
+        _specialOptions: [
+            'fileInput',
+            'dropZone',
+            'pasteZone',
+            'multipart',
+            'forceIframeTransport'
+        ],
+
+        _blobSlice: $.support.blobSlice && function () {
+            var slice = this.slice || this.webkitSlice || this.mozSlice;
+            return slice.apply(this, arguments);
+        },
+
+        _BitrateTimer: function () {
+            this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
+            this.loaded = 0;
+            this.bitrate = 0;
+            this.getBitrate = function (now, loaded, interval) {
+                var timeDiff = now - this.timestamp;
+                if (!this.bitrate || !interval || timeDiff > interval) {
+                    this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
+                    this.loaded = loaded;
+                    this.timestamp = now;
+                }
+                return this.bitrate;
+            };
+        },
+
+        _isXHRUpload: function (options) {
+            return !options.forceIframeTransport &&
+                ((!options.multipart && $.support.xhrFileUpload) ||
+                $.support.xhrFormDataFileUpload);
+        },
+
+        _getFormData: function (options) {
+            var formData;
+            if ($.type(options.formData) === 'function') {
+                return options.formData(options.form);
+            }
+            if ($.isArray(options.formData)) {
+                return options.formData;
+            }
+            if ($.type(options.formData) === 'object') {
+                formData = [];
+                $.each(options.formData, function (name, value) {
+                    formData.push({name: name, value: value});
+                });
+                return formData;
+            }
+            return [];
+        },
+
+        _getTotal: function (files) {
+            var total = 0;
+            $.each(files, function (index, file) {
+                total += file.size || 1;
+            });
+            return total;
+        },
+
+        _initProgressObject: function (obj) {
+            var progress = {
+                loaded: 0,
+                total: 0,
+                bitrate: 0
+            };
+            if (obj._progress) {
+                $.extend(obj._progress, progress);
+            } else {
+                obj._progress = progress;
+            }
+        },
+
+        _initResponseObject: function (obj) {
+            var prop;
+            if (obj._response) {
+                for (prop in obj._response) {
+                    if (obj._response.hasOwnProperty(prop)) {
+                        delete obj._response[prop];
+                    }
+                }
+            } else {
+                obj._response = {};
+            }
+        },
+
+        _onProgress: function (e, data) {
+            if (e.lengthComputable) {
+                var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
+                    loaded;
+                if (data._time && data.progressInterval &&
+                        (now - data._time < data.progressInterval) &&
+                        e.loaded !== e.total) {
+                    return;
+                }
+                data._time = now;
+                loaded = Math.floor(
+                    e.loaded / e.total * (data.chunkSize || data._progress.total)
+                ) + (data.uploadedBytes || 0);
+                // Add the difference from the previously loaded state
+                // to the global loaded counter:
+                this._progress.loaded += (loaded - data._progress.loaded);
+                this._progress.bitrate = this._bitrateTimer.getBitrate(
+                    now,
+                    this._progress.loaded,
+                    data.bitrateInterval
+                );
+                data._progress.loaded = data.loaded = loaded;
+                data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
+                    now,
+                    loaded,
+                    data.bitrateInterval
+                );
+                // Trigger a custom progress event with a total data property set
+                // to the file size(s) of the current upload and a loaded data
+                // property calculated accordingly:
+                this._trigger(
+                    'progress',
+                    $.Event('progress', {delegatedEvent: e}),
+                    data
+                );
+                // Trigger a global progress event for all current file uploads,
+                // including ajax calls queued for sequential file uploads:
+                this._trigger(
+                    'progressall',
+                    $.Event('progressall', {delegatedEvent: e}),
+                    this._progress
+                );
+            }
+        },
+
+        _initProgressListener: function (options) {
+            var that = this,
+                xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
+            // Accesss to the native XHR object is required to add event listeners
+            // for the upload progress event:
+            if (xhr.upload) {
+                $(xhr.upload).bind('progress', function (e) {
+                    var oe = e.originalEvent;
+                    // Make sure the progress event properties get copied over:
+                    e.lengthComputable = oe.lengthComputable;
+                    e.loaded = oe.loaded;
+                    e.total = oe.total;
+                    that._onProgress(e, options);
+                });
+                options.xhr = function () {
+                    return xhr;
+                };
+            }
+        },
+
+        _isInstanceOf: function (type, obj) {
+            // Cross-frame instanceof check
+            return Object.prototype.toString.call(obj) === '[object ' + type + ']';
+        },
+
+        _initXHRData: function (options) {
+            var that = this,
+                formData,
+                file = options.files[0],
+                // Ignore non-multipart setting if not supported:
+                multipart = options.multipart || !$.support.xhrFileUpload,
+                paramName = $.type(options.paramName) === 'array' ?
+                    options.paramName[0] : options.paramName;
+            options.headers = $.extend({}, options.headers);
+            if (options.contentRange) {
+                options.headers['Content-Range'] = options.contentRange;
+            }
+            if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
+                options.headers['Content-Disposition'] = 'attachment; filename="' +
+                    encodeURI(file.uploadName || file.name) + '"';
+            }
+            if (!multipart) {
+                options.contentType = file.type || 'application/octet-stream';
+                options.data = options.blob || file;
+            } else if ($.support.xhrFormDataFileUpload) {
+                if (options.postMessage) {
+                    // window.postMessage does not allow sending FormData
+                    // objects, so we just add the File/Blob objects to
+                    // the formData array and let the postMessage window
+                    // create the FormData object out of this array:
+                    formData = this._getFormData(options);
+                    if (options.blob) {
+                        formData.push({
+                            name: paramName,
+                            value: options.blob
+                        });
+                    } else {
+                        $.each(options.files, function (index, file) {
+                            formData.push({
+                                name: ($.type(options.paramName) === 'array' &&
+                                    options.paramName[index]) || paramName,
+                                value: file
+                            });
+                        });
+                    }
+                } else {
+                    if (that._isInstanceOf('FormData', options.formData)) {
+                        formData = options.formData;
+                    } else {
+                        formData = new FormData();
+                        $.each(this._getFormData(options), function (index, field) {
+                            formData.append(field.name, field.value);
+                        });
+                    }
+                    if (options.blob) {
+                        formData.append(
+                            paramName,
+                            options.blob,
+                            file.uploadName || file.name
+                        );
+                    } else {
+                        $.each(options.files, function (index, file) {
+                            // This check allows the tests to run with
+                            // dummy objects:
+                            if (that._isInstanceOf('File', file) ||
+                                    that._isInstanceOf('Blob', file)) {
+                                formData.append(
+                                    ($.type(options.paramName) === 'array' &&
+                                        options.paramName[index]) || paramName,
+                                    file,
+                                    file.uploadName || file.name
+                                );
+                            }
+                        });
+                    }
+                }
+                options.data = formData;
+            }
+            // Blob reference is not needed anymore, free memory:
+            options.blob = null;
+        },
+
+        _initIframeSettings: function (options) {
+            var targetHost = $('<a></a>').prop('href', options.url).prop('host');
+            // Setting the dataType to iframe enables the iframe transport:
+            options.dataType = 'iframe ' + (options.dataType || '');
+            // The iframe transport accepts a serialized array as form data:
+            options.formData = this._getFormData(options);
+            // Add redirect url to form data on cross-domain uploads:
+            if (options.redirect && targetHost && targetHost !== location.host) {
+                options.formData.push({
+                    name: options.redirectParamName || 'redirect',
+                    value: options.redirect
+                });
+            }
+        },
+
+        _initDataSettings: function (options) {
+            if (this._isXHRUpload(options)) {
+                if (!this._chunkedUpload(options, true)) {
+                    if (!options.data) {
+                        this._initXHRData(options);
+                    }
+                    this._initProgressListener(options);
+                }
+                if (options.postMessage) {
+                    // Setting the dataType to postmessage enables the
+                    // postMessage transport:
+                    options.dataType = 'postmessage ' + (options.dataType || '');
+                }
+            } else {
+                this._initIframeSettings(options);
+            }
+        },
+
+        _getParamName: function (options) {
+            var fileInput = $(options.fileInput),
+                paramName = options.paramName;
+            if (!paramName) {
+                paramName = [];
+                fileInput.each(function () {
+                    var input = $(this),
+                        name = input.prop('name') || 'files[]',
+                        i = (input.prop('files') || [1]).length;
+                    while (i) {
+                        paramName.push(name);
+                        i -= 1;
+                    }
+                });
+                if (!paramName.length) {
+                    paramName = [fileInput.prop('name') || 'files[]'];
+                }
+            } else if (!$.isArray(paramName)) {
+                paramName = [paramName];
+            }
+            return paramName;
+        },
+
+        _initFormSettings: function (options) {
+            // Retrieve missing options from the input field and the
+            // associated form, if available:
+            if (!options.form || !options.form.length) {
+                options.form = $(options.fileInput.prop('form'));
+                // If the given file input doesn't have an associated form,
+                // use the default widget file input's form:
+                if (!options.form.length) {
+                    options.form = $(this.options.fileInput.prop('form'));
+                }
+            }
+            options.paramName = this._getParamName(options);
+            if (!options.url) {
+                options.url = options.form.prop('action') || location.href;
+            }
+            // The HTTP request method must be "POST" or "PUT":
+            options.type = (options.type ||
+                ($.type(options.form.prop('method')) === 'string' &&
+                    options.form.prop('method')) || ''
+                ).toUpperCase();
+            if (options.type !== 'POST' && options.type !== 'PUT' &&
+                    options.type !== 'PATCH') {
+                options.type = 'POST';
+            }
+            if (!options.formAcceptCharset) {
+                options.formAcceptCharset = options.form.attr('accept-charset');
+            }
+        },
+
+        _getAJAXSettings: function (data) {
+            var options = $.extend({}, this.options, data);
+            this._initFormSettings(options);
+            this._initDataSettings(options);
+            return options;
+        },
+
+        // jQuery 1.6 doesn't provide .state(),
+        // while jQuery 1.8+ removed .isRejected() and .isResolved():
+        _getDeferredState: function (deferred) {
+            if (deferred.state) {
+                return deferred.state();
+            }
+            if (deferred.isResolved()) {
+                return 'resolved';
+            }
+            if (deferred.isRejected()) {
+                return 'rejected';
+            }
+            return 'pending';
+        },
+
+        // Maps jqXHR callbacks to the equivalent
+        // methods of the given Promise object:
+        _enhancePromise: function (promise) {
+            promise.success = promise.done;
+            promise.error = promise.fail;
+            promise.complete = promise.always;
+            return promise;
+        },
+
+        // Creates and returns a Promise object enhanced with
+        // the jqXHR methods abort, success, error and complete:
+        _getXHRPromise: function (resolveOrReject, context, args) {
+            var dfd = $.Deferred(),
+                promise = dfd.promise();
+            context = context || this.options.context || promise;
+            if (resolveOrReject === true) {
+                dfd.resolveWith(context, args);
+            } else if (resolveOrReject === false) {
+                dfd.rejectWith(context, args);
+            }
+            promise.abort = dfd.promise;
+            return this._enhancePromise(promise);
+        },
+
+        // Adds convenience methods to the data callback argument:
+        _addConvenienceMethods: function (e, data) {
+            var that = this,
+                getPromise = function (args) {
+                    return $.Deferred().resolveWith(that, args).promise();
+                };
+            data.process = function (resolveFunc, rejectFunc) {
+                if (resolveFunc || rejectFunc) {
+                    data._processQueue = this._processQueue =
+                        (this._processQueue || getPromise([this])).then(
+                            function () {
+                                if (data.errorThrown) {
+                                    return $.Deferred()
+                                        .rejectWith(that, [data]).promise();
+                                }
+                                return getPromise(arguments);
+                            }
+                        ).then(resolveFunc, rejectFunc);
+                }
+                return this._processQueue || getPromise([this]);
+            };
+            data.submit = function () {
+                if (this.state() !== 'pending') {
+                    data.jqXHR = this.jqXHR =
+                        (that._trigger(
+                            'submit',
+                            $.Event('submit', {delegatedEvent: e}),
+                            this
+                        ) !== false) && that._onSend(e, this);
+                }
+                return this.jqXHR || that._getXHRPromise();
+            };
+            data.abort = function () {
+                if (this.jqXHR) {
+                    return this.jqXHR.abort();
+                }
+                this.errorThrown = 'abort';
+                that._trigger('fail', null, this);
+                return that._getXHRPromise(false);
+            };
+            data.state = function () {
+                if (this.jqXHR) {
+                    return that._getDeferredState(this.jqXHR);
+                }
+                if (this._processQueue) {
+                    return that._getDeferredState(this._processQueue);
+                }
+            };
+            data.processing = function () {
+                return !this.jqXHR && this._processQueue && that
+                    ._getDeferredState(this._processQueue) === 'pending';
+            };
+            data.progress = function () {
+                return this._progress;
+            };
+            data.response = function () {
+                return this._response;
+            };
+        },
+
+        // Parses the Range header from the server response
+        // and returns the uploaded bytes:
+        _getUploadedBytes: function (jqXHR) {
+            var range = jqXHR.getResponseHeader('Range'),
+                parts = range && range.split('-'),
+                upperBytesPos = parts && parts.length > 1 &&
+                    parseInt(parts[1], 10);
+            return upperBytesPos && upperBytesPos + 1;
+        },
+
+        // Uploads a file in multiple, sequential requests
+        // by splitting the file up in multiple blob chunks.
+        // If the second parameter is true, only tests if the file
+        // should be uploaded in chunks, but does not invoke any
+        // upload requests:
+        _chunkedUpload: function (options, testOnly) {
+            options.uploadedBytes = options.uploadedBytes || 0;
+            var that = this,
+                file = options.files[0],
+                fs = file.size,
+                ub = options.uploadedBytes,
+                mcs = options.maxChunkSize || fs,
+                slice = this._blobSlice,
+                dfd = $.Deferred(),
+                promise = dfd.promise(),
+                jqXHR,
+                upload;
+            if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) ||
+                    options.data) {
+                return false;
+            }
+            if (testOnly) {
+                return true;
+            }
+            if (ub >= fs) {
+                file.error = options.i18n('uploadedBytes');
+                return this._getXHRPromise(
+                    false,
+                    options.context,
+                    [null, 'error', file.error]
+                );
+            }
+            // The chunk upload method:
+            upload = function () {
+                // Clone the options object for each chunk upload:
+                var o = $.extend({}, options),
+                    currentLoaded = o._progress.loaded;
+                o.blob = slice.call(
+                    file,
+                    ub,
+                    ub + ($.type(mcs) === 'function' ? mcs(o) : mcs),
+                    file.type
+                );
+                // Store the current chunk size, as the blob itself
+                // will be dereferenced after data processing:
+                o.chunkSize = o.blob.size;
+                // Expose the chunk bytes position range:
+                o.contentRange = 'bytes ' + ub + '-' +
+                    (ub + o.chunkSize - 1) + '/' + fs;
+                // Process the upload data (the blob and potential form data):
+                that._initXHRData(o);
+                // Add progress listeners for this chunk upload:
+                that._initProgressListener(o);
+                jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||
+                        that._getXHRPromise(false, o.context))
+                    .done(function (result, textStatus, jqXHR) {
+                        ub = that._getUploadedBytes(jqXHR) ||
+                            (ub + o.chunkSize);
+                        // Create a progress event if no final progress event
+                        // with loaded equaling total has been triggered
+                        // for this chunk:
+                        if (currentLoaded + o.chunkSize - o._progress.loaded) {
+                            that._onProgress($.Event('progress', {
+                                lengthComputable: true,
+                                loaded: ub - o.uploadedBytes,
+                                total: ub - o.uploadedBytes
+                            }), o);
+                        }
+                        options.uploadedBytes = o.uploadedBytes = ub;
+                        o.result = result;
+                        o.textStatus = textStatus;
+                        o.jqXHR = jqXHR;
+                        that._trigger('chunkdone', null, o);
+                        that._trigger('chunkalways', null, o);
+                        if (ub < fs) {
+                            // File upload not yet complete,
+                            // continue with the next chunk:
+                            upload();
+                        } else {
+                            dfd.resolveWith(
+                                o.context,
+                                [result, textStatus, jqXHR]
+                            );
+                        }
+                    })
+                    .fail(function (jqXHR, textStatus, errorThrown) {
+                        o.jqXHR = jqXHR;
+                        o.textStatus = textStatus;
+                        o.errorThrown = errorThrown;
+                        that._trigger('chunkfail', null, o);
+                        that._trigger('chunkalways', null, o);
+                        dfd.rejectWith(
+                            o.context,
+                            [jqXHR, textStatus, errorThrown]
+                        );
+                    });
+            };
+            this._enhancePromise(promise);
+            promise.abort = function () {
+                return jqXHR.abort();
+            };
+            upload();
+            return promise;
+        },
+
+        _beforeSend: function (e, data) {
+            if (this._active === 0) {
+                // the start callback is triggered when an upload starts
+                // and no other uploads are currently running,
+                // equivalent to the global ajaxStart event:
+                this._trigger('start');
+                // Set timer for global bitrate progress calculation:
+                this._bitrateTimer = new this._BitrateTimer();
+                // Reset the global progress values:
+                this._progress.loaded = this._progress.total = 0;
+                this._progress.bitrate = 0;
+            }
+            // Make sure the container objects for the .response() and
+            // .progress() methods on the data object are available
+            // and reset to their initial state:
+            this._initResponseObject(data);
+            this._initProgressObject(data);
+            data._progress.loaded = data.loaded = data.uploadedBytes || 0;
+            data._progress.total = data.total = this._getTotal(data.files) || 1;
+            data._progress.bitrate = data.bitrate = 0;
+            this._active += 1;
+            // Initialize the global progress values:
+            this._progress.loaded += data.loaded;
+            this._progress.total += data.total;
+        },
+
+        _onDone: function (result, textStatus, jqXHR, options) {
+            var total = options._progress.total,
+                response = options._response;
+            if (options._progress.loaded < total) {
+                // Create a progress event if no final progress event
+                // with loaded equaling total has been triggered:
+                this._onProgress($.Event('progress', {
+                    lengthComputable: true,
+                    loaded: total,
+                    total: total
+                }), options);
+            }
+            response.result = options.result = result;
+            response.textStatus = options.textStatus = textStatus;
+            response.jqXHR = options.jqXHR = jqXHR;
+            this._trigger('done', null, options);
+        },
+
+        _onFail: function (jqXHR, textStatus, errorThrown, options) {
+            var response = options._response;
+            if (options.recalculateProgress) {
+                // Remove the failed (error or abort) file upload from
+                // the global progress calculation:
+                this._progress.loaded -= options._progress.loaded;
+                this._progress.total -= options._progress.total;
+            }
+            response.jqXHR = options.jqXHR = jqXHR;
+            response.textStatus = options.textStatus = textStatus;
+            response.errorThrown = options.errorThrown = errorThrown;
+            this._trigger('fail', null, options);
+        },
+
+        _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
+            // jqXHRorResult, textStatus and jqXHRorError are added to the
+            // options object via done and fail callbacks
+            this._trigger('always', null, options);
+        },
+
+        _onSend: function (e, data) {
+            if (!data.submit) {
+                this._addConvenienceMethods(e, data);
+            }
+            var that = this,
+                jqXHR,
+                aborted,
+                slot,
+                pipe,
+                options = that._getAJAXSettings(data),
+                send = function () {
+                    that._sending += 1;
+                    // Set timer for bitrate progress calculation:
+                    options._bitrateTimer = new that._BitrateTimer();
+                    jqXHR = jqXHR || (
+                        ((aborted || that._trigger(
+                            'send',
+                            $.Event('send', {delegatedEvent: e}),
+                            options
+                        ) === false) &&
+                        that._getXHRPromise(false, options.context, aborted)) ||
+                        that._chunkedUpload(options) || $.ajax(options)
+                    ).done(function (result, textStatus, jqXHR) {
+                        that._onDone(result, textStatus, jqXHR, options);
+                    }).fail(function (jqXHR, textStatus, errorThrown) {
+                        that._onFail(jqXHR, textStatus, errorThrown, options);
+                    }).always(function (jqXHRorResult, textStatus, jqXHRorError) {
+                        that._onAlways(
+                            jqXHRorResult,
+                            textStatus,
+                            jqXHRorError,
+                            options
+                        );
+                        that._sending -= 1;
+                        that._active -= 1;
+                        if (options.limitConcurrentUploads &&
+                                options.limitConcurrentUploads > that._sending) {
+                            // Start the next queued upload,
+                            // that has not been aborted:
+                            var nextSlot = that._slots.shift();
+                            while (nextSlot) {
+                                if (that._getDeferredState(nextSlot) === 'pending') {
+                                    nextSlot.resolve();
+                                    break;
+                                }
+                                nextSlot = that._slots.shift();
+                            }
+                        }
+                        if (that._active === 0) {
+                            // The stop callback is triggered when all uploads have
+                            // been completed, equivalent to the global ajaxStop event:
+                            that._trigger('stop');
+                        }
+                    });
+                    return jqXHR;
+                };
+            this._beforeSend(e, options);
+            if (this.options.sequentialUploads ||
+                    (this.options.limitConcurrentUploads &&
+                    this.options.limitConcurrentUploads <= this._sending)) {
+                if (this.options.limitConcurrentUploads > 1) {
+                    slot = $.Deferred();
+                    this._slots.push(slot);
+                    pipe = slot.then(send);
+                } else {
+                    this._sequence = this._sequence.then(send, send);
+                    pipe = this._sequence;
+                }
+                // Return the piped Promise object, enhanced with an abort method,
+                // which is delegated to the jqXHR object of the current upload,
+                // and jqXHR callbacks mapped to the equivalent Promise methods:
+                pipe.abort = function () {
+                    aborted = [undefined, 'abort', 'abort'];
+                    if (!jqXHR) {
+                        if (slot) {
+                            slot.rejectWith(options.context, aborted);
+                        }
+                        return send();
+                    }
+                    return jqXHR.abort();
+                };
+                return this._enhancePromise(pipe);
+            }
+            return send();
+        },
+
+        _onAdd: function (e, data) {
+            var that = this,
+                result = true,
+                options = $.extend({}, this.options, data),
+                files = data.files,
+                filesLength = files.length,
+                limit = options.limitMultiFileUploads,
+                limitSize = options.limitMultiFileUploadSize,
+                overhead = options.limitMultiFileUploadSizeOverhead,
+                batchSize = 0,
+                paramName = this._getParamName(options),
+                paramNameSet,
+                paramNameSlice,
+                fileSet,
+                i,
+                j = 0;
+            if (!filesLength) {
+                return false;
+            }
+            if (limitSize && files[0].size === undefined) {
+                limitSize = undefined;
+            }
+            if (!(options.singleFileUploads || limit || limitSize) ||
+                    !this._isXHRUpload(options)) {
+                fileSet = [files];
+                paramNameSet = [paramName];
+            } else if (!(options.singleFileUploads || limitSize) && limit) {
+                fileSet = [];
+                paramNameSet = [];
+                for (i = 0; i < filesLength; i += limit) {
+                    fileSet.push(files.slice(i, i + limit));
+                    paramNameSlice = paramName.slice(i, i + limit);
+                    if (!paramNameSlice.length) {
+                        paramNameSlice = paramName;
+                    }
+                    paramNameSet.push(paramNameSlice);
+                }
+            } else if (!options.singleFileUploads && limitSize) {
+                fileSet = [];
+                paramNameSet = [];
+                for (i = 0; i < filesLength; i = i + 1) {
+                    batchSize += files[i].size + overhead;
+                    if (i + 1 === filesLength ||
+                            ((batchSize + files[i + 1].size + overhead) > limitSize) ||
+                            (limit && i + 1 - j >= limit)) {
+                        fileSet.push(files.slice(j, i + 1));
+                        paramNameSlice = paramName.slice(j, i + 1);
+                        if (!paramNameSlice.length) {
+                            paramNameSlice = paramName;
+                        }
+                        paramNameSet.push(paramNameSlice);
+                        j = i + 1;
+                        batchSize = 0;
+                    }
+                }
+            } else {
+                paramNameSet = paramName;
+            }
+            data.originalFiles = files;
+            $.each(fileSet || files, function (index, element) {
+                var newData = $.extend({}, data);
+                newData.files = fileSet ? element : [element];
+                newData.paramName = paramNameSet[index];
+                that._initResponseObject(newData);
+                that._initProgressObject(newData);
+                that._addConvenienceMethods(e, newData);
+                result = that._trigger(
+                    'add',
+                    $.Event('add', {delegatedEvent: e}),
+                    newData
+                );
+                return result;
+            });
+            return result;
+        },
+
+        _replaceFileInput: function (data) {
+            var input = data.fileInput,
+                inputClone = input.clone(true),
+                restoreFocus = input.is(document.activeElement);
+            // Add a reference for the new cloned file input to the data argument:
+            data.fileInputClone = inputClone;
+            $('<form></form>').append(inputClone)[0].reset();
+            // Detaching allows to insert the fileInput on another form
+            // without loosing the file input value:
+            input.after(inputClone).detach();
+            // If the fileInput had focus before it was detached,
+            // restore focus to the inputClone.
+            if (restoreFocus) {
+                inputClone.focus();
+            }
+            // Avoid memory leaks with the detached file input:
+            $.cleanData(input.unbind('remove'));
+            // Replace the original file input element in the fileInput
+            // elements set with the clone, which has been copied including
+            // event handlers:
+            this.options.fileInput = this.options.fileInput.map(function (i, el) {
+                if (el === input[0]) {
+                    return inputClone[0];
+                }
+                return el;
+            });
+            // If the widget has been initialized on the file input itself,
+            // override this.element with the file input clone:
+            if (input[0] === this.element[0]) {
+                this.element = inputClone;
+            }
+        },
+
+        _handleFileTreeEntry: function (entry, path) {
+            var that = this,
+                dfd = $.Deferred(),
+                entries = [],
+                dirReader,
+                errorHandler = function (e) {
+                    if (e && !e.entry) {
+                        e.entry = entry;
+                    }
+                    // Since $.when returns immediately if one
+                    // Deferred is rejected, we use resolve instead.
+                    // This allows valid files and invalid items
+                    // to be returned together in one set:
+                    dfd.resolve([e]);
+                },
+                successHandler = function (entries) {
+                    that._handleFileTreeEntries(
+                        entries,
+                        path + entry.name + '/'
+                    ).done(function (files) {
+                        dfd.resolve(files);
+                    }).fail(errorHandler);
+                },
+                readEntries = function () {
+                    dirReader.readEntries(function (results) {
+                        if (!results.length) {
+                            successHandler(entries);
+                        } else {
+                            entries = entries.concat(results);
+                            readEntries();
+                        }
+                    }, errorHandler);
+                };
+            path = path || '';
+            if (entry.isFile) {
+                if (entry._file) {
+                    // Workaround for Chrome bug #149735
+                    entry._file.relativePath = path;
+                    dfd.resolve(entry._file);
+                } else {
+                    entry.file(function (file) {
+                        file.relativePath = path;
+                        dfd.resolve(file);
+                    }, errorHandler);
+                }
+            } else if (entry.isDirectory) {
+                dirReader = entry.createReader();
+                readEntries();
+            } else {
+                // Return an empy list for file system items
+                // other than files or directories:
+                dfd.resolve([]);
+            }
+            return dfd.promise();
+        },
+
+        _handleFileTreeEntries: function (entries, path) {
+            var that = this;
+            return $.when.apply(
+                $,
+                $.map(entries, function (entry) {
+                    return that._handleFileTreeEntry(entry, path);
+                })
+            ).then(function () {
+                return Array.prototype.concat.apply(
+                    [],
+                    arguments
+                );
+            });
+        },
+
+        _getDroppedFiles: function (dataTransfer) {
+            dataTransfer = dataTransfer || {};
+            var items = dataTransfer.items;
+            if (items && items.length && (items[0].webkitGetAsEntry ||
+                    items[0].getAsEntry)) {
+                return this._handleFileTreeEntries(
+                    $.map(items, function (item) {
+                        var entry;
+                        if (item.webkitGetAsEntry) {
+                            entry = item.webkitGetAsEntry();
+                            if (entry) {
+                                // Workaround for Chrome bug #149735:
+                                entry._file = item.getAsFile();
+                            }
+                            return entry;
+                        }
+                        return item.getAsEntry();
+                    })
+                );
+            }
+            return $.Deferred().resolve(
+                $.makeArray(dataTransfer.files)
+            ).promise();
+        },
+
+        _getSingleFileInputFiles: function (fileInput) {
+            fileInput = $(fileInput);
+            var entries = fileInput.prop('webkitEntries') ||
+                    fileInput.prop('entries'),
+                files,
+                value;
+            if (entries && entries.length) {
+                return this._handleFileTreeEntries(entries);
+            }
+            files = $.makeArray(fileInput.prop('files'));
+            if (!files.length) {
+                value = fileInput.prop('value');
+                if (!value) {
+                    return $.Deferred().resolve([]).promise();
+                }
+                // If the files property is not available, the browser does not
+                // support the File API and we add a pseudo File object with
+                // the input value as name with path information removed:
+                files = [{name: value.replace(/^.*\\/, '')}];
+            } else if (files[0].name === undefined && files[0].fileName) {
+                // File normalization for Safari 4 and Firefox 3:
+                $.each(files, function (index, file) {
+                    file.name = file.fileName;
+                    file.size = file.fileSize;
+                });
+            }
+            return $.Deferred().resolve(files).promise();
+        },
+
+        _getFileInputFiles: function (fileInput) {
+            if (!(fileInput instanceof $) || fileInput.length === 1) {
+                return this._getSingleFileInputFiles(fileInput);
+            }
+            return $.when.apply(
+                $,
+                $.map(fileInput, this._getSingleFileInputFiles)
+            ).then(function () {
+                return Array.prototype.concat.apply(
+                    [],
+                    arguments
+                );
+            });
+        },
+
+        _onChange: function (e) {
+            var that = this,
+                data = {
+                    fileInput: $(e.target),
+                    form: $(e.target.form)
+                };
+            this._getFileInputFiles(data.fileInput).always(function (files) {
+                data.files = files;
+                if (that.options.replaceFileInput) {
+                    that._replaceFileInput(data);
+                }
+                if (that._trigger(
+                        'change',
+                        $.Event('change', {delegatedEvent: e}),
+                        data
+                    ) !== false) {
+                    that._onAdd(e, data);
+                }
+            });
+        },
+
+        _onPaste: function (e) {
+            var items = e.originalEvent && e.originalEvent.clipboardData &&
+                    e.originalEvent.clipboardData.items,
+                data = {files: []};
+            if (items && items.length) {
+                $.each(items, function (index, item) {
+                    var file = item.getAsFile && item.getAsFile();
+                    if (file) {
+                        data.files.push(file);
+                    }
+                });
+                if (this._trigger(
+                        'paste',
+                        $.Event('paste', {delegatedEvent: e}),
+                        data
+                    ) !== false) {
+                    this._onAdd(e, data);
+                }
+            }
+        },
+
+        _onDrop: function (e) {
+            e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
+            var that = this,
+                dataTransfer = e.dataTransfer,
+                data = {};
+            if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
+                e.preventDefault();
+                this._getDroppedFiles(dataTransfer).always(function (files) {
+                    data.files = files;
+                    if (that._trigger(
+                            'drop',
+                            $.Event('drop', {delegatedEvent: e}),
+                            data
+                        ) !== false) {
+                        that._onAdd(e, data);
+                    }
+                });
+            }
+        },
+
+        _onDragOver: getDragHandler('dragover'),
+
+        _onDragEnter: getDragHandler('dragenter'),
+
+        _onDragLeave: getDragHandler('dragleave'),
+
+        _initEventHandlers: function () {
+            if (this._isXHRUpload(this.options)) {
+                this._on(this.options.dropZone, {
+                    dragover: this._onDragOver,
+                    drop: this._onDrop,
+                    // event.preventDefault() on dragenter is required for IE10+:
+                    dragenter: this._onDragEnter,
+                    // dragleave is not required, but added for completeness:
+                    dragleave: this._onDragLeave
+                });
+                this._on(this.options.pasteZone, {
+                    paste: this._onPaste
+                });
+            }
+            if ($.support.fileInput) {
+                this._on(this.options.fileInput, {
+                    change: this._onChange
+                });
+            }
+        },
+
+        _destroyEventHandlers: function () {
+            this._off(this.options.dropZone, 'dragenter dragleave dragover drop');
+            this._off(this.options.pasteZone, 'paste');
+            this._off(this.options.fileInput, 'change');
+        },
+
+        _destroy: function () {
+            this._destroyEventHandlers();
+        },
+
+        _setOption: function (key, value) {
+            var reinit = $.inArray(key, this._specialOptions) !== -1;
+            if (reinit) {
+                this._destroyEventHandlers();
+            }
+            this._super(key, value);
+            if (reinit) {
+                this._initSpecialOptions();
+                this._initEventHandlers();
+            }
+        },
+
+        _initSpecialOptions: function () {
+            var options = this.options;
+            if (options.fileInput === undefined) {
+                options.fileInput = this.element.is('input[type="file"]') ?
+                        this.element : this.element.find('input[type="file"]');
+            } else if (!(options.fileInput instanceof $)) {
+                options.fileInput = $(options.fileInput);
+            }
+            if (!(options.dropZone instanceof $)) {
+                options.dropZone = $(options.dropZone);
+            }
+            if (!(options.pasteZone instanceof $)) {
+                options.pasteZone = $(options.pasteZone);
+            }
+        },
+
+        _getRegExp: function (str) {
+            var parts = str.split('/'),
+                modifiers = parts.pop();
+            parts.shift();
+            return new RegExp(parts.join('/'), modifiers);
+        },
+
+        _isRegExpOption: function (key, value) {
+            return key !== 'url' && $.type(value) === 'string' &&
+                /^\/.*\/[igm]{0,3}$/.test(value);
+        },
+
+        _initDataAttributes: function () {
+            var that = this,
+                options = this.options,
+                data = this.element.data();
+            // Initialize options set via HTML5 data-attributes:
+            $.each(
+                this.element[0].attributes,
+                function (index, attr) {
+                    var key = attr.name.toLowerCase(),
+                        value;
+                    if (/^data-/.test(key)) {
+                        // Convert hyphen-ated key to camelCase:
+                        key = key.slice(5).replace(/-[a-z]/g, function (str) {
+                            return str.charAt(1).toUpperCase();
+                        });
+                        value = data[key];
+                        if (that._isRegExpOption(key, value)) {
+                            value = that._getRegExp(value);
+                        }
+                        options[key] = value;
+                    }
+                }
+            );
+        },
+
+        _create: function () {
+            this._initDataAttributes();
+            this._initSpecialOptions();
+            this._slots = [];
+            this._sequence = this._getXHRPromise(true);
+            this._sending = this._active = 0;
+            this._initProgressObject(this);
+            this._initEventHandlers();
+        },
+
+        // This method is exposed to the widget API and allows to query
+        // the number of active uploads:
+        active: function () {
+            return this._active;
+        },
+
+        // This method is exposed to the widget API and allows to query
+        // the widget upload progress.
+        // It returns an object with loaded, total and bitrate properties
+        // for the running uploads:
+        progress: function () {
+            return this._progress;
+        },
+
+        // This method is exposed to the widget API and allows adding files
+        // using the fileupload API. The data parameter accepts an object which
+        // must have a files property and can contain additional options:
+        // .fileupload('add', {files: filesList});
+        add: function (data) {
+            var that = this;
+            if (!data || this.options.disabled) {
+                return;
+            }
+            if (data.fileInput && !data.files) {
+                this._getFileInputFiles(data.fileInput).always(function (files) {
+                    data.files = files;
+                    that._onAdd(null, data);
+                });
+            } else {
+                data.files = $.makeArray(data.files);
+                this._onAdd(null, data);
+            }
+        },
+
+        // This method is exposed to the widget API and allows sending files
+        // using the fileupload API. The data parameter accepts an object which
+        // must have a files or fileInput property and can contain additional options:
+        // .fileupload('send', {files: filesList});
+        // The method returns a Promise object for the file upload call.
+        send: function (data) {
+            if (data && !this.options.disabled) {
+                if (data.fileInput && !data.files) {
+                    var that = this,
+                        dfd = $.Deferred(),
+                        promise = dfd.promise(),
+                        jqXHR,
+                        aborted;
+                    promise.abort = function () {
+                        aborted = true;
+                        if (jqXHR) {
+                            return jqXHR.abort();
+                        }
+                        dfd.reject(null, 'abort', 'abort');
+                        return promise;
+                    };
+                    this._getFileInputFiles(data.fileInput).always(
+                        function (files) {
+                            if (aborted) {
+                                return;
+                            }
+                            if (!files.length) {
+                                dfd.reject();
+                                return;
+                            }
+                            data.files = files;
+                            jqXHR = that._onSend(null, data);
+                            jqXHR.then(
+                                function (result, textStatus, jqXHR) {
+                                    dfd.resolve(result, textStatus, jqXHR);
+                                },
+                                function (jqXHR, textStatus, errorThrown) {
+                                    dfd.reject(jqXHR, textStatus, errorThrown);
+                                }
+                            );
+                        }
+                    );
+                    return this._enhancePromise(promise);
+                }
+                data.files = $.makeArray(data.files);
+                if (data.files.length) {
+                    return this._onSend(null, data);
+                }
+            }
+            return this._getXHRPromise(false, data && data.context);
+        }
+
+    });
+
+}));

+ 224 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/jquery.iframe-transport.js

@@ -0,0 +1,224 @@
+/*
+ * jQuery Iframe Transport Plugin
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* global define, require, window, document, JSON */
+
+;(function (factory) {
+    'use strict';
+    if (typeof define === 'function' && define.amd) {
+        // Register as an anonymous AMD module:
+        define(['jquery'], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS:
+        factory(require('jquery'));
+    } else {
+        // Browser globals:
+        factory(window.jQuery);
+    }
+}(function ($) {
+    'use strict';
+
+    // Helper variable to create unique names for the transport iframes:
+    var counter = 0,
+        jsonAPI = $,
+        jsonParse = 'parseJSON';
+
+    if ('JSON' in window && 'parse' in JSON) {
+      jsonAPI = JSON;
+      jsonParse = 'parse';
+    }
+
+    // The iframe transport accepts four additional options:
+    // options.fileInput: a jQuery collection of file input fields
+    // options.paramName: the parameter name for the file form data,
+    //  overrides the name property of the file input field(s),
+    //  can be a string or an array of strings.
+    // options.formData: an array of objects with name and value properties,
+    //  equivalent to the return data of .serializeArray(), e.g.:
+    //  [{name: 'a', value: 1}, {name: 'b', value: 2}]
+    // options.initialIframeSrc: the URL of the initial iframe src,
+    //  by default set to "javascript:false;"
+    $.ajaxTransport('iframe', function (options) {
+        if (options.async) {
+            // javascript:false as initial iframe src
+            // prevents warning popups on HTTPS in IE6:
+            /*jshint scripturl: true */
+            var initialIframeSrc = options.initialIframeSrc || 'javascript:false;',
+            /*jshint scripturl: false */
+                form,
+                iframe,
+                addParamChar;
+            return {
+                send: function (_, completeCallback) {
+                    form = $('<form style="display:none;"></form>');
+                    form.attr('accept-charset', options.formAcceptCharset);
+                    addParamChar = /\?/.test(options.url) ? '&' : '?';
+                    // XDomainRequest only supports GET and POST:
+                    if (options.type === 'DELETE') {
+                        options.url = options.url + addParamChar + '_method=DELETE';
+                        options.type = 'POST';
+                    } else if (options.type === 'PUT') {
+                        options.url = options.url + addParamChar + '_method=PUT';
+                        options.type = 'POST';
+                    } else if (options.type === 'PATCH') {
+                        options.url = options.url + addParamChar + '_method=PATCH';
+                        options.type = 'POST';
+                    }
+                    // IE versions below IE8 cannot set the name property of
+                    // elements that have already been added to the DOM,
+                    // so we set the name along with the iframe HTML markup:
+                    counter += 1;
+                    iframe = $(
+                        '<iframe src="' + initialIframeSrc +
+                            '" name="iframe-transport-' + counter + '"></iframe>'
+                    ).bind('load', function () {
+                        var fileInputClones,
+                            paramNames = $.isArray(options.paramName) ?
+                                    options.paramName : [options.paramName];
+                        iframe
+                            .unbind('load')
+                            .bind('load', function () {
+                                var response;
+                                // Wrap in a try/catch block to catch exceptions thrown
+                                // when trying to access cross-domain iframe contents:
+                                try {
+                                    response = iframe.contents();
+                                    // Google Chrome and Firefox do not throw an
+                                    // exception when calling iframe.contents() on
+                                    // cross-domain requests, so we unify the response:
+                                    if (!response.length || !response[0].firstChild) {
+                                        throw new Error();
+                                    }
+                                } catch (e) {
+                                    response = undefined;
+                                }
+                                // The complete callback returns the
+                                // iframe content document as response object:
+                                completeCallback(
+                                    200,
+                                    'success',
+                                    {'iframe': response}
+                                );
+                                // Fix for IE endless progress bar activity bug
+                                // (happens on form submits to iframe targets):
+                                $('<iframe src="' + initialIframeSrc + '"></iframe>')
+                                    .appendTo(form);
+                                window.setTimeout(function () {
+                                    // Removing the form in a setTimeout call
+                                    // allows Chrome's developer tools to display
+                                    // the response result
+                                    form.remove();
+                                }, 0);
+                            });
+                        form
+                            .prop('target', iframe.prop('name'))
+                            .prop('action', options.url)
+                            .prop('method', options.type);
+                        if (options.formData) {
+                            $.each(options.formData, function (index, field) {
+                                $('<input type="hidden"/>')
+                                    .prop('name', field.name)
+                                    .val(field.value)
+                                    .appendTo(form);
+                            });
+                        }
+                        if (options.fileInput && options.fileInput.length &&
+                                options.type === 'POST') {
+                            fileInputClones = options.fileInput.clone();
+                            // Insert a clone for each file input field:
+                            options.fileInput.after(function (index) {
+                                return fileInputClones[index];
+                            });
+                            if (options.paramName) {
+                                options.fileInput.each(function (index) {
+                                    $(this).prop(
+                                        'name',
+                                        paramNames[index] || options.paramName
+                                    );
+                                });
+                            }
+                            // Appending the file input fields to the hidden form
+                            // removes them from their original location:
+                            form
+                                .append(options.fileInput)
+                                .prop('enctype', 'multipart/form-data')
+                                // enctype must be set as encoding for IE:
+                                .prop('encoding', 'multipart/form-data');
+                            // Remove the HTML5 form attribute from the input(s):
+                            options.fileInput.removeAttr('form');
+                        }
+                        form.submit();
+                        // Insert the file input fields at their original location
+                        // by replacing the clones with the originals:
+                        if (fileInputClones && fileInputClones.length) {
+                            options.fileInput.each(function (index, input) {
+                                var clone = $(fileInputClones[index]);
+                                // Restore the original name and form properties:
+                                $(input)
+                                    .prop('name', clone.prop('name'))
+                                    .attr('form', clone.attr('form'));
+                                clone.replaceWith(input);
+                            });
+                        }
+                    });
+                    form.append(iframe).appendTo(document.body);
+                },
+                abort: function () {
+                    if (iframe) {
+                        // javascript:false as iframe src aborts the request
+                        // and prevents warning popups on HTTPS in IE6.
+                        // concat is used to avoid the "Script URL" JSLint error:
+                        iframe
+                            .unbind('load')
+                            .prop('src', initialIframeSrc);
+                    }
+                    if (form) {
+                        form.remove();
+                    }
+                }
+            };
+        }
+    });
+
+    // The iframe transport returns the iframe content document as response.
+    // The following adds converters from iframe to text, json, html, xml
+    // and script.
+    // Please note that the Content-Type for JSON responses has to be text/plain
+    // or text/html, if the browser doesn't include application/json in the
+    // Accept header, else IE will show a download dialog.
+    // The Content-Type for XML responses on the other hand has to be always
+    // application/xml or text/xml, so IE properly parses the XML response.
+    // See also
+    // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation
+    $.ajaxSetup({
+        converters: {
+            'iframe text': function (iframe) {
+                return iframe && $(iframe[0].body).text();
+            },
+            'iframe json': function (iframe) {
+                return iframe && jsonAPI[jsonParse]($(iframe[0].body).text());
+            },
+            'iframe html': function (iframe) {
+                return iframe && $(iframe[0].body).html();
+            },
+            'iframe xml': function (iframe) {
+                var xmlDoc = iframe && iframe[0];
+                return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc :
+                        $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) ||
+                            $(xmlDoc.body).html());
+            },
+            'iframe script': function (iframe) {
+                return iframe && $.globalEval($(iframe[0].body).text());
+            }
+        }
+    });
+
+}));

+ 75 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/main.js

@@ -0,0 +1,75 @@
+/*
+ * jQuery File Upload Plugin JS Example
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* global $, window */
+
+$(function () {
+    'use strict';
+
+    // Initialize the jQuery File Upload widget:
+    $('#fileupload').fileupload({
+        // Uncomment the following to send cross-domain cookies:
+        //xhrFields: {withCredentials: true},
+        url: 'server/php/'
+    });
+
+    // Enable iframe cross-domain access via redirect option:
+    $('#fileupload').fileupload(
+        'option',
+        'redirect',
+        window.location.href.replace(
+            /\/[^\/]*$/,
+            '/cors/result.html?%s'
+        )
+    );
+
+    if (window.location.hostname === 'blueimp.github.io') {
+        // Demo settings:
+        $('#fileupload').fileupload('option', {
+            url: '//jquery-file-upload.appspot.com/',
+            // Enable image resizing, except for Android and Opera,
+            // which actually support image resizing, but fail to
+            // send Blob objects via XHR requests:
+            disableImageResize: /Android(?!.*Chrome)|Opera/
+                .test(window.navigator.userAgent),
+            maxFileSize: 999000,
+            acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
+        });
+        // Upload server status check for browsers with CORS support:
+        if ($.support.cors) {
+            $.ajax({
+                url: '//jquery-file-upload.appspot.com/',
+                type: 'HEAD'
+            }).fail(function () {
+                $('<div class="alert alert-danger"/>')
+                    .text('Upload server currently unavailable - ' +
+                            new Date())
+                    .appendTo('#fileupload');
+            });
+        }
+    } else {
+        // Load existing files:
+        $('#fileupload').addClass('fileupload-processing');
+        $.ajax({
+            // Uncomment the following to send cross-domain cookies:
+            //xhrFields: {withCredentials: true},
+            url: $('#fileupload').fileupload('option', 'url'),
+            dataType: 'json',
+            context: $('#fileupload')[0]
+        }).always(function () {
+            $(this).removeClass('fileupload-processing');
+        }).done(function (result) {
+            $(this).fileupload('option', 'done')
+                .call(this, $.Event('done'), {result: result});
+        });
+    }
+
+});

+ 572 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/js/vendor/jquery.ui.widget.js

@@ -0,0 +1,572 @@
+/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28
+* http://jqueryui.com
+* Includes: widget.js
+* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
+
+(function( factory ) {
+	if ( typeof define === "function" && define.amd ) {
+
+		// AMD. Register as an anonymous module.
+		define([ "jquery" ], factory );
+
+	} else if ( typeof exports === "object" ) {
+
+		// Node/CommonJS
+		factory( require( "jquery" ) );
+
+	} else {
+
+		// Browser globals
+		factory( jQuery );
+	}
+}(function( $ ) {
+/*!
+ * jQuery UI Widget 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/jQuery.widget/
+ */
+
+
+var widget_uuid = 0,
+	widget_slice = Array.prototype.slice;
+
+$.cleanData = (function( orig ) {
+	return function( elems ) {
+		var events, elem, i;
+		for ( i = 0; (elem = elems[i]) != null; i++ ) {
+			try {
+
+				// Only trigger remove when necessary to save time
+				events = $._data( elem, "events" );
+				if ( events && events.remove ) {
+					$( elem ).triggerHandler( "remove" );
+				}
+
+			// http://bugs.jquery.com/ticket/8235
+			} catch ( e ) {}
+		}
+		orig( elems );
+	};
+})( $.cleanData );
+
+$.widget = function( name, base, prototype ) {
+	var fullName, existingConstructor, constructor, basePrototype,
+		// proxiedPrototype allows the provided prototype to remain unmodified
+		// so that it can be used as a mixin for multiple widgets (#8876)
+		proxiedPrototype = {},
+		namespace = name.split( "." )[ 0 ];
+
+	name = name.split( "." )[ 1 ];
+	fullName = namespace + "-" + name;
+
+	if ( !prototype ) {
+		prototype = base;
+		base = $.Widget;
+	}
+
+	// create selector for plugin
+	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+		return !!$.data( elem, fullName );
+	};
+
+	$[ namespace ] = $[ namespace ] || {};
+	existingConstructor = $[ namespace ][ name ];
+	constructor = $[ namespace ][ name ] = function( options, element ) {
+		// allow instantiation without "new" keyword
+		if ( !this._createWidget ) {
+			return new constructor( options, element );
+		}
+
+		// allow instantiation without initializing for simple inheritance
+		// must use "new" keyword (the code above always passes args)
+		if ( arguments.length ) {
+			this._createWidget( options, element );
+		}
+	};
+	// extend with the existing constructor to carry over any static properties
+	$.extend( constructor, existingConstructor, {
+		version: prototype.version,
+		// copy the object used to create the prototype in case we need to
+		// redefine the widget later
+		_proto: $.extend( {}, prototype ),
+		// track widgets that inherit from this widget in case this widget is
+		// redefined after a widget inherits from it
+		_childConstructors: []
+	});
+
+	basePrototype = new base();
+	// we need to make the options hash a property directly on the new instance
+	// otherwise we'll modify the options hash on the prototype that we're
+	// inheriting from
+	basePrototype.options = $.widget.extend( {}, basePrototype.options );
+	$.each( prototype, function( prop, value ) {
+		if ( !$.isFunction( value ) ) {
+			proxiedPrototype[ prop ] = value;
+			return;
+		}
+		proxiedPrototype[ prop ] = (function() {
+			var _super = function() {
+					return base.prototype[ prop ].apply( this, arguments );
+				},
+				_superApply = function( args ) {
+					return base.prototype[ prop ].apply( this, args );
+				};
+			return function() {
+				var __super = this._super,
+					__superApply = this._superApply,
+					returnValue;
+
+				this._super = _super;
+				this._superApply = _superApply;
+
+				returnValue = value.apply( this, arguments );
+
+				this._super = __super;
+				this._superApply = __superApply;
+
+				return returnValue;
+			};
+		})();
+	});
+	constructor.prototype = $.widget.extend( basePrototype, {
+		// TODO: remove support for widgetEventPrefix
+		// always use the name + a colon as the prefix, e.g., draggable:start
+		// don't prefix for widgets that aren't DOM-based
+		widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
+	}, proxiedPrototype, {
+		constructor: constructor,
+		namespace: namespace,
+		widgetName: name,
+		widgetFullName: fullName
+	});
+
+	// If this widget is being redefined then we need to find all widgets that
+	// are inheriting from it and redefine all of them so that they inherit from
+	// the new version of this widget. We're essentially trying to replace one
+	// level in the prototype chain.
+	if ( existingConstructor ) {
+		$.each( existingConstructor._childConstructors, function( i, child ) {
+			var childPrototype = child.prototype;
+
+			// redefine the child widget using the same prototype that was
+			// originally used, but inherit from the new version of the base
+			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+		});
+		// remove the list of existing child constructors from the old constructor
+		// so the old child constructors can be garbage collected
+		delete existingConstructor._childConstructors;
+	} else {
+		base._childConstructors.push( constructor );
+	}
+
+	$.widget.bridge( name, constructor );
+
+	return constructor;
+};
+
+$.widget.extend = function( target ) {
+	var input = widget_slice.call( arguments, 1 ),
+		inputIndex = 0,
+		inputLength = input.length,
+		key,
+		value;
+	for ( ; inputIndex < inputLength; inputIndex++ ) {
+		for ( key in input[ inputIndex ] ) {
+			value = input[ inputIndex ][ key ];
+			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+				// Clone objects
+				if ( $.isPlainObject( value ) ) {
+					target[ key ] = $.isPlainObject( target[ key ] ) ?
+						$.widget.extend( {}, target[ key ], value ) :
+						// Don't extend strings, arrays, etc. with objects
+						$.widget.extend( {}, value );
+				// Copy everything else by reference
+				} else {
+					target[ key ] = value;
+				}
+			}
+		}
+	}
+	return target;
+};
+
+$.widget.bridge = function( name, object ) {
+	var fullName = object.prototype.widgetFullName || name;
+	$.fn[ name ] = function( options ) {
+		var isMethodCall = typeof options === "string",
+			args = widget_slice.call( arguments, 1 ),
+			returnValue = this;
+
+		if ( isMethodCall ) {
+			this.each(function() {
+				var methodValue,
+					instance = $.data( this, fullName );
+				if ( options === "instance" ) {
+					returnValue = instance;
+					return false;
+				}
+				if ( !instance ) {
+					return $.error( "cannot call methods on " + name + " prior to initialization; " +
+						"attempted to call method '" + options + "'" );
+				}
+				if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+					return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+				}
+				methodValue = instance[ options ].apply( instance, args );
+				if ( methodValue !== instance && methodValue !== undefined ) {
+					returnValue = methodValue && methodValue.jquery ?
+						returnValue.pushStack( methodValue.get() ) :
+						methodValue;
+					return false;
+				}
+			});
+		} else {
+
+			// Allow multiple hashes to be passed on init
+			if ( args.length ) {
+				options = $.widget.extend.apply( null, [ options ].concat(args) );
+			}
+
+			this.each(function() {
+				var instance = $.data( this, fullName );
+				if ( instance ) {
+					instance.option( options || {} );
+					if ( instance._init ) {
+						instance._init();
+					}
+				} else {
+					$.data( this, fullName, new object( options, this ) );
+				}
+			});
+		}
+
+		return returnValue;
+	};
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+	widgetName: "widget",
+	widgetEventPrefix: "",
+	defaultElement: "<div>",
+	options: {
+		disabled: false,
+
+		// callbacks
+		create: null
+	},
+	_createWidget: function( options, element ) {
+		element = $( element || this.defaultElement || this )[ 0 ];
+		this.element = $( element );
+		this.uuid = widget_uuid++;
+		this.eventNamespace = "." + this.widgetName + this.uuid;
+
+		this.bindings = $();
+		this.hoverable = $();
+		this.focusable = $();
+
+		if ( element !== this ) {
+			$.data( element, this.widgetFullName, this );
+			this._on( true, this.element, {
+				remove: function( event ) {
+					if ( event.target === element ) {
+						this.destroy();
+					}
+				}
+			});
+			this.document = $( element.style ?
+				// element within the document
+				element.ownerDocument :
+				// element is window or document
+				element.document || element );
+			this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+		}
+
+		this.options = $.widget.extend( {},
+			this.options,
+			this._getCreateOptions(),
+			options );
+
+		this._create();
+		this._trigger( "create", null, this._getCreateEventData() );
+		this._init();
+	},
+	_getCreateOptions: $.noop,
+	_getCreateEventData: $.noop,
+	_create: $.noop,
+	_init: $.noop,
+
+	destroy: function() {
+		this._destroy();
+		// we can probably remove the unbind calls in 2.0
+		// all event bindings should go through this._on()
+		this.element
+			.unbind( this.eventNamespace )
+			.removeData( this.widgetFullName )
+			// support: jquery <1.6.3
+			// http://bugs.jquery.com/ticket/9413
+			.removeData( $.camelCase( this.widgetFullName ) );
+		this.widget()
+			.unbind( this.eventNamespace )
+			.removeAttr( "aria-disabled" )
+			.removeClass(
+				this.widgetFullName + "-disabled " +
+				"ui-state-disabled" );
+
+		// clean up events and states
+		this.bindings.unbind( this.eventNamespace );
+		this.hoverable.removeClass( "ui-state-hover" );
+		this.focusable.removeClass( "ui-state-focus" );
+	},
+	_destroy: $.noop,
+
+	widget: function() {
+		return this.element;
+	},
+
+	option: function( key, value ) {
+		var options = key,
+			parts,
+			curOption,
+			i;
+
+		if ( arguments.length === 0 ) {
+			// don't return a reference to the internal hash
+			return $.widget.extend( {}, this.options );
+		}
+
+		if ( typeof key === "string" ) {
+			// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+			options = {};
+			parts = key.split( "." );
+			key = parts.shift();
+			if ( parts.length ) {
+				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+				for ( i = 0; i < parts.length - 1; i++ ) {
+					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+					curOption = curOption[ parts[ i ] ];
+				}
+				key = parts.pop();
+				if ( arguments.length === 1 ) {
+					return curOption[ key ] === undefined ? null : curOption[ key ];
+				}
+				curOption[ key ] = value;
+			} else {
+				if ( arguments.length === 1 ) {
+					return this.options[ key ] === undefined ? null : this.options[ key ];
+				}
+				options[ key ] = value;
+			}
+		}
+
+		this._setOptions( options );
+
+		return this;
+	},
+	_setOptions: function( options ) {
+		var key;
+
+		for ( key in options ) {
+			this._setOption( key, options[ key ] );
+		}
+
+		return this;
+	},
+	_setOption: function( key, value ) {
+		this.options[ key ] = value;
+
+		if ( key === "disabled" ) {
+			this.widget()
+				.toggleClass( this.widgetFullName + "-disabled", !!value );
+
+			// If the widget is becoming disabled, then nothing is interactive
+			if ( value ) {
+				this.hoverable.removeClass( "ui-state-hover" );
+				this.focusable.removeClass( "ui-state-focus" );
+			}
+		}
+
+		return this;
+	},
+
+	enable: function() {
+		return this._setOptions({ disabled: false });
+	},
+	disable: function() {
+		return this._setOptions({ disabled: true });
+	},
+
+	_on: function( suppressDisabledCheck, element, handlers ) {
+		var delegateElement,
+			instance = this;
+
+		// no suppressDisabledCheck flag, shuffle arguments
+		if ( typeof suppressDisabledCheck !== "boolean" ) {
+			handlers = element;
+			element = suppressDisabledCheck;
+			suppressDisabledCheck = false;
+		}
+
+		// no element argument, shuffle and use this.element
+		if ( !handlers ) {
+			handlers = element;
+			element = this.element;
+			delegateElement = this.widget();
+		} else {
+			element = delegateElement = $( element );
+			this.bindings = this.bindings.add( element );
+		}
+
+		$.each( handlers, function( event, handler ) {
+			function handlerProxy() {
+				// allow widgets to customize the disabled handling
+				// - disabled as an array instead of boolean
+				// - disabled class as method for disabling individual parts
+				if ( !suppressDisabledCheck &&
+						( instance.options.disabled === true ||
+							$( this ).hasClass( "ui-state-disabled" ) ) ) {
+					return;
+				}
+				return ( typeof handler === "string" ? instance[ handler ] : handler )
+					.apply( instance, arguments );
+			}
+
+			// copy the guid so direct unbinding works
+			if ( typeof handler !== "string" ) {
+				handlerProxy.guid = handler.guid =
+					handler.guid || handlerProxy.guid || $.guid++;
+			}
+
+			var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
+				eventName = match[1] + instance.eventNamespace,
+				selector = match[2];
+			if ( selector ) {
+				delegateElement.delegate( selector, eventName, handlerProxy );
+			} else {
+				element.bind( eventName, handlerProxy );
+			}
+		});
+	},
+
+	_off: function( element, eventName ) {
+		eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
+			this.eventNamespace;
+		element.unbind( eventName ).undelegate( eventName );
+
+		// Clear the stack to avoid memory leaks (#10056)
+		this.bindings = $( this.bindings.not( element ).get() );
+		this.focusable = $( this.focusable.not( element ).get() );
+		this.hoverable = $( this.hoverable.not( element ).get() );
+	},
+
+	_delay: function( handler, delay ) {
+		function handlerProxy() {
+			return ( typeof handler === "string" ? instance[ handler ] : handler )
+				.apply( instance, arguments );
+		}
+		var instance = this;
+		return setTimeout( handlerProxy, delay || 0 );
+	},
+
+	_hoverable: function( element ) {
+		this.hoverable = this.hoverable.add( element );
+		this._on( element, {
+			mouseenter: function( event ) {
+				$( event.currentTarget ).addClass( "ui-state-hover" );
+			},
+			mouseleave: function( event ) {
+				$( event.currentTarget ).removeClass( "ui-state-hover" );
+			}
+		});
+	},
+
+	_focusable: function( element ) {
+		this.focusable = this.focusable.add( element );
+		this._on( element, {
+			focusin: function( event ) {
+				$( event.currentTarget ).addClass( "ui-state-focus" );
+			},
+			focusout: function( event ) {
+				$( event.currentTarget ).removeClass( "ui-state-focus" );
+			}
+		});
+	},
+
+	_trigger: function( type, event, data ) {
+		var prop, orig,
+			callback = this.options[ type ];
+
+		data = data || {};
+		event = $.Event( event );
+		event.type = ( type === this.widgetEventPrefix ?
+			type :
+			this.widgetEventPrefix + type ).toLowerCase();
+		// the original event may come from any element
+		// so we need to reset the target on the new event
+		event.target = this.element[ 0 ];
+
+		// copy original event properties over to the new event
+		orig = event.originalEvent;
+		if ( orig ) {
+			for ( prop in orig ) {
+				if ( !( prop in event ) ) {
+					event[ prop ] = orig[ prop ];
+				}
+			}
+		}
+
+		this.element.trigger( event, data );
+		return !( $.isFunction( callback ) &&
+			callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+			event.isDefaultPrevented() );
+	}
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+		if ( typeof options === "string" ) {
+			options = { effect: options };
+		}
+		var hasOptions,
+			effectName = !options ?
+				method :
+				options === true || typeof options === "number" ?
+					defaultEffect :
+					options.effect || defaultEffect;
+		options = options || {};
+		if ( typeof options === "number" ) {
+			options = { duration: options };
+		}
+		hasOptions = !$.isEmptyObject( options );
+		options.complete = callback;
+		if ( options.delay ) {
+			element.delay( options.delay );
+		}
+		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+			element[ method ]( options );
+		} else if ( effectName !== method && element[ effectName ] ) {
+			element[ effectName ]( options.duration, options.easing, callback );
+		} else {
+			element.queue(function( next ) {
+				$( this )[ method ]();
+				if ( callback ) {
+					callback.call( element[ 0 ] );
+				}
+				next();
+			});
+		}
+	};
+});
+
+var widget = $.widget;
+
+
+
+}));

+ 55 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/package.json

@@ -0,0 +1,55 @@
+{
+  "name": "blueimp-file-upload",
+  "version": "9.19.2",
+  "title": "jQuery File Upload",
+  "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
+  "keywords": [
+    "jquery",
+    "file",
+    "upload",
+    "widget",
+    "multiple",
+    "selection",
+    "drag",
+    "drop",
+    "progress",
+    "preview",
+    "cross-domain",
+    "cross-site",
+    "chunk",
+    "resume",
+    "gae",
+    "go",
+    "python",
+    "php",
+    "bootstrap"
+  ],
+  "homepage": "https://github.com/blueimp/jQuery-File-Upload",
+  "author": {
+    "name": "Sebastian Tschan",
+    "url": "https://blueimp.net"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/blueimp/jQuery-File-Upload.git"
+  },
+  "license": "MIT",
+  "optionalDependencies": {
+    "blueimp-canvas-to-blob": "3.5.0",
+    "blueimp-load-image": "2.12.2",
+    "blueimp-tmpl": "3.6.0"
+  },
+  "devDependencies": {
+    "bower-json": "0.8.1",
+    "jshint": "2.9.3"
+  },
+  "scripts": {
+    "bower-version-update": "./bower-version-update.js",
+    "lint": "jshint *.js js/*.js js/cors/*.js",
+    "test": "npm run lint",
+    "preversion": "npm test",
+    "version": "npm run bower-version-update && git add bower.json",
+    "postversion": "git push --tags origin master && npm publish"
+  },
+  "main": "js/jquery.fileupload.js"
+}

+ 12 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/app.yaml

@@ -0,0 +1,12 @@
+application: jquery-file-upload
+version: 2
+runtime: go
+api_version: go1
+
+handlers:
+- url: /(favicon\.ico|robots\.txt)
+  static_files: static/\1
+  upload: static/(.*)
+  expiration: '1d'
+- url: /.*
+  script: _go_app

+ 361 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/app/main.go

@@ -0,0 +1,361 @@
+/*
+ * jQuery File Upload Plugin GAE Go Example
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+package app
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"github.com/disintegration/gift"
+	"golang.org/x/net/context"
+	"google.golang.org/appengine"
+	"google.golang.org/appengine/memcache"
+	"hash/crc32"
+	"image"
+	"image/gif"
+	"image/jpeg"
+	"image/png"
+	"io"
+	"log"
+	"mime/multipart"
+	"net/http"
+	"net/url"
+	"path/filepath"
+	"regexp"
+	"strings"
+)
+
+const (
+	WEBSITE       = "https://blueimp.github.io/jQuery-File-Upload/"
+	MIN_FILE_SIZE = 1 // bytes
+	// Max file size is memcache limit (1MB) minus key size minus overhead:
+	MAX_FILE_SIZE     = 999000 // bytes
+	IMAGE_TYPES       = "image/(gif|p?jpeg|(x-)?png)"
+	ACCEPT_FILE_TYPES = IMAGE_TYPES
+	THUMB_MAX_WIDTH   = 80
+	THUMB_MAX_HEIGHT  = 80
+	EXPIRATION_TIME   = 300 // seconds
+	// If empty, only allow redirects to the referer protocol+host.
+	// Set to a regexp string for custom pattern matching:
+	REDIRECT_ALLOW_TARGET = ""
+)
+
+var (
+	imageTypes      = regexp.MustCompile(IMAGE_TYPES)
+	acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES)
+	thumbSuffix     = "." + fmt.Sprint(THUMB_MAX_WIDTH) + "x" +
+		fmt.Sprint(THUMB_MAX_HEIGHT)
+)
+
+func escape(s string) string {
+	return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
+}
+
+func extractKey(r *http.Request) string {
+	// Use RequestURI instead of r.URL.Path, as we need the encoded form:
+	path := strings.Split(r.RequestURI, "?")[0]
+	// Also adjust double encoded slashes:
+	return strings.Replace(path[1:], "%252F", "%2F", -1)
+}
+
+func check(err error) {
+	if err != nil {
+		panic(err)
+	}
+}
+
+type FileInfo struct {
+	Key          string `json:"-"`
+	ThumbnailKey string `json:"-"`
+	Url          string `json:"url,omitempty"`
+	ThumbnailUrl string `json:"thumbnailUrl,omitempty"`
+	Name         string `json:"name"`
+	Type         string `json:"type"`
+	Size         int64  `json:"size"`
+	Error        string `json:"error,omitempty"`
+	DeleteUrl    string `json:"deleteUrl,omitempty"`
+	DeleteType   string `json:"deleteType,omitempty"`
+}
+
+func (fi *FileInfo) ValidateType() (valid bool) {
+	if acceptFileTypes.MatchString(fi.Type) {
+		return true
+	}
+	fi.Error = "Filetype not allowed"
+	return false
+}
+
+func (fi *FileInfo) ValidateSize() (valid bool) {
+	if fi.Size < MIN_FILE_SIZE {
+		fi.Error = "File is too small"
+	} else if fi.Size > MAX_FILE_SIZE {
+		fi.Error = "File is too big"
+	} else {
+		return true
+	}
+	return false
+}
+
+func (fi *FileInfo) CreateUrls(r *http.Request, c context.Context) {
+	u := &url.URL{
+		Scheme: r.URL.Scheme,
+		Host:   appengine.DefaultVersionHostname(c),
+		Path:   "/",
+	}
+	uString := u.String()
+	fi.Url = uString + fi.Key
+	fi.DeleteUrl = fi.Url
+	fi.DeleteType = "DELETE"
+	if fi.ThumbnailKey != "" {
+		fi.ThumbnailUrl = uString + fi.ThumbnailKey
+	}
+}
+
+func (fi *FileInfo) SetKey(checksum uint32) {
+	fi.Key = escape(string(fi.Type)) + "/" +
+		escape(fmt.Sprint(checksum)) + "/" +
+		escape(string(fi.Name))
+}
+
+func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c context.Context) {
+	if imageTypes.MatchString(fi.Type) {
+		src, _, err := image.Decode(bytes.NewReader(buffer.Bytes()))
+		check(err)
+		filter := gift.New(gift.ResizeToFit(
+			THUMB_MAX_WIDTH,
+			THUMB_MAX_HEIGHT,
+			gift.LanczosResampling,
+		))
+		dst := image.NewNRGBA(filter.Bounds(src.Bounds()))
+		filter.Draw(dst, src)
+		buffer.Reset()
+		bWriter := bufio.NewWriter(buffer)
+		switch fi.Type {
+		case "image/jpeg", "image/pjpeg":
+			err = jpeg.Encode(bWriter, dst, nil)
+		case "image/gif":
+			err = gif.Encode(bWriter, dst, nil)
+		default:
+			err = png.Encode(bWriter, dst)
+		}
+		check(err)
+		bWriter.Flush()
+		thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name)
+		item := &memcache.Item{
+			Key:   thumbnailKey,
+			Value: buffer.Bytes(),
+		}
+		err = memcache.Set(c, item)
+		check(err)
+		fi.ThumbnailKey = thumbnailKey
+	}
+}
+
+func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
+	fi = &FileInfo{
+		Name: p.FileName(),
+		Type: p.Header.Get("Content-Type"),
+	}
+	if !fi.ValidateType() {
+		return
+	}
+	defer func() {
+		if rec := recover(); rec != nil {
+			log.Println(rec)
+			fi.Error = rec.(error).Error()
+		}
+	}()
+	var buffer bytes.Buffer
+	hash := crc32.NewIEEE()
+	mw := io.MultiWriter(&buffer, hash)
+	lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1}
+	_, err := io.Copy(mw, lr)
+	check(err)
+	fi.Size = MAX_FILE_SIZE + 1 - lr.N
+	if !fi.ValidateSize() {
+		return
+	}
+	fi.SetKey(hash.Sum32())
+	item := &memcache.Item{
+		Key:   fi.Key,
+		Value: buffer.Bytes(),
+	}
+	context := appengine.NewContext(r)
+	err = memcache.Set(context, item)
+	check(err)
+	fi.createThumb(&buffer, context)
+	fi.CreateUrls(r, context)
+	return
+}
+
+func getFormValue(p *multipart.Part) string {
+	var b bytes.Buffer
+	io.CopyN(&b, p, int64(1<<20)) // Copy max: 1 MiB
+	return b.String()
+}
+
+func handleUploads(r *http.Request) (fileInfos []*FileInfo) {
+	fileInfos = make([]*FileInfo, 0)
+	mr, err := r.MultipartReader()
+	check(err)
+	r.Form, err = url.ParseQuery(r.URL.RawQuery)
+	check(err)
+	part, err := mr.NextPart()
+	for err == nil {
+		if name := part.FormName(); name != "" {
+			if part.FileName() != "" {
+				fileInfos = append(fileInfos, handleUpload(r, part))
+			} else {
+				r.Form[name] = append(r.Form[name], getFormValue(part))
+			}
+		}
+		part, err = mr.NextPart()
+	}
+	return
+}
+
+func validateRedirect(r *http.Request, redirect string) bool {
+	if redirect != "" {
+		var redirectAllowTarget *regexp.Regexp
+		if REDIRECT_ALLOW_TARGET != "" {
+			redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET)
+		} else {
+			referer := r.Referer()
+			if referer == "" {
+				return false
+			}
+			refererUrl, err := url.Parse(referer)
+			if err != nil {
+				return false
+			}
+			redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta(
+				refererUrl.Scheme+"://"+refererUrl.Host+"/",
+			))
+		}
+		return redirectAllowTarget.MatchString(redirect)
+	}
+	return false
+}
+
+func get(w http.ResponseWriter, r *http.Request) {
+	if r.URL.Path == "/" {
+		http.Redirect(w, r, WEBSITE, http.StatusFound)
+		return
+	}
+	// Use RequestURI instead of r.URL.Path, as we need the encoded form:
+	key := extractKey(r)
+	parts := strings.Split(key, "/")
+	if len(parts) == 3 {
+		context := appengine.NewContext(r)
+		item, err := memcache.Get(context, key)
+		if err == nil {
+			w.Header().Add("X-Content-Type-Options", "nosniff")
+			contentType, _ := url.QueryUnescape(parts[0])
+			if !imageTypes.MatchString(contentType) {
+				contentType = "application/octet-stream"
+			}
+			w.Header().Add("Content-Type", contentType)
+			w.Header().Add(
+				"Cache-Control",
+				fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME),
+			)
+			w.Write(item.Value)
+			return
+		}
+	}
+	http.Error(w, "404 Not Found", http.StatusNotFound)
+}
+
+func post(w http.ResponseWriter, r *http.Request) {
+	result := make(map[string][]*FileInfo, 1)
+	result["files"] = handleUploads(r)
+	b, err := json.Marshal(result)
+	check(err)
+	if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) {
+		if strings.Contains(redirect, "%s") {
+			redirect = fmt.Sprintf(
+				redirect,
+				escape(string(b)),
+			)
+		}
+		http.Redirect(w, r, redirect, http.StatusFound)
+		return
+	}
+	w.Header().Set("Cache-Control", "no-cache")
+	jsonType := "application/json"
+	if strings.Index(r.Header.Get("Accept"), jsonType) != -1 {
+		w.Header().Set("Content-Type", jsonType)
+	}
+	fmt.Fprintln(w, string(b))
+}
+
+func delete(w http.ResponseWriter, r *http.Request) {
+	key := extractKey(r)
+	parts := strings.Split(key, "/")
+	if len(parts) == 3 {
+		result := make(map[string]bool, 1)
+		context := appengine.NewContext(r)
+		err := memcache.Delete(context, key)
+		if err == nil {
+			result[key] = true
+			contentType, _ := url.QueryUnescape(parts[0])
+			if imageTypes.MatchString(contentType) {
+				thumbnailKey := key + thumbSuffix + filepath.Ext(parts[2])
+				err := memcache.Delete(context, thumbnailKey)
+				if err == nil {
+					result[thumbnailKey] = true
+				}
+			}
+		}
+		w.Header().Set("Content-Type", "application/json")
+		b, err := json.Marshal(result)
+		check(err)
+		fmt.Fprintln(w, string(b))
+	} else {
+		http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed)
+	}
+}
+
+func handle(w http.ResponseWriter, r *http.Request) {
+	params, err := url.ParseQuery(r.URL.RawQuery)
+	check(err)
+	w.Header().Add("Access-Control-Allow-Origin", "*")
+	w.Header().Add(
+		"Access-Control-Allow-Methods",
+		"OPTIONS, HEAD, GET, POST, DELETE",
+	)
+	w.Header().Add(
+		"Access-Control-Allow-Headers",
+		"Content-Type, Content-Range, Content-Disposition",
+	)
+	switch r.Method {
+	case "OPTIONS", "HEAD":
+		return
+	case "GET":
+		get(w, r)
+	case "POST":
+		if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" {
+			delete(w, r)
+		} else {
+			post(w, r)
+		}
+	case "DELETE":
+		delete(w, r)
+	default:
+		http.Error(w, "501 Not Implemented", http.StatusNotImplemented)
+	}
+}
+
+func init() {
+	http.HandleFunc("/", handle)
+}

二进制
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/static/favicon.ico


+ 2 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-go/static/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow:

+ 17 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/app.yaml

@@ -0,0 +1,17 @@
+application: jquery-file-upload
+version: 1
+runtime: python27
+api_version: 1
+threadsafe: true
+
+libraries:
+- name: PIL
+  version: latest
+
+handlers:
+- url: /(favicon\.ico|robots\.txt)
+  static_files: static/\1
+  upload: static/(.*)
+  expiration: '1d'
+- url: /.*
+  script: main.app

+ 204 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/main.py

@@ -0,0 +1,204 @@
+# -*- coding: utf-8 -*-
+#
+# jQuery File Upload Plugin GAE Python Example
+# https://github.com/blueimp/jQuery-File-Upload
+#
+# Copyright 2011, Sebastian Tschan
+# https://blueimp.net
+#
+# Licensed under the MIT license:
+# https://opensource.org/licenses/MIT
+#
+
+from google.appengine.api import memcache, images
+import json
+import os
+import re
+import urllib
+import webapp2
+
+DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev')
+WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/'
+MIN_FILE_SIZE = 1  # bytes
+# Max file size is memcache limit (1MB) minus key size minus overhead:
+MAX_FILE_SIZE = 999000  # bytes
+IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
+ACCEPT_FILE_TYPES = IMAGE_TYPES
+THUMB_MAX_WIDTH = 80
+THUMB_MAX_HEIGHT = 80
+THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png'
+EXPIRATION_TIME = 300  # seconds
+# If set to None, only allow redirects to the referer protocol+host.
+# Set to a regexp for custom pattern matching against the redirect value:
+REDIRECT_ALLOW_TARGET = None
+
+class CORSHandler(webapp2.RequestHandler):
+    def cors(self):
+        headers = self.response.headers
+        headers['Access-Control-Allow-Origin'] = '*'
+        headers['Access-Control-Allow-Methods'] =\
+            'OPTIONS, HEAD, GET, POST, DELETE'
+        headers['Access-Control-Allow-Headers'] =\
+            'Content-Type, Content-Range, Content-Disposition'
+
+    def initialize(self, request, response):
+        super(CORSHandler, self).initialize(request, response)
+        self.cors()
+
+    def json_stringify(self, obj):
+        return json.dumps(obj, separators=(',', ':'))
+
+    def options(self, *args, **kwargs):
+        pass
+
+class UploadHandler(CORSHandler):
+    def validate(self, file):
+        if file['size'] < MIN_FILE_SIZE:
+            file['error'] = 'File is too small'
+        elif file['size'] > MAX_FILE_SIZE:
+            file['error'] = 'File is too big'
+        elif not ACCEPT_FILE_TYPES.match(file['type']):
+            file['error'] = 'Filetype not allowed'
+        else:
+            return True
+        return False
+
+    def validate_redirect(self, redirect):
+        if redirect:
+            if REDIRECT_ALLOW_TARGET:
+                return REDIRECT_ALLOW_TARGET.match(redirect)
+            referer = self.request.headers['referer']
+            if referer:
+                from urlparse import urlparse
+                parts = urlparse(referer)
+                redirect_allow_target = '^' + re.escape(
+                    parts.scheme + '://' + parts.netloc + '/'
+                )
+            return re.match(redirect_allow_target, redirect)
+        return False
+
+    def get_file_size(self, file):
+        file.seek(0, 2)  # Seek to the end of the file
+        size = file.tell()  # Get the position of EOF
+        file.seek(0)  # Reset the file position to the beginning
+        return size
+
+    def write_blob(self, data, info):
+        key = urllib.quote(info['type'].encode('utf-8'), '') +\
+            '/' + str(hash(data)) +\
+            '/' + urllib.quote(info['name'].encode('utf-8'), '')
+        try:
+            memcache.set(key, data, time=EXPIRATION_TIME)
+        except: #Failed to add to memcache
+            return (None, None)
+        thumbnail_key = None
+        if IMAGE_TYPES.match(info['type']):
+            try:
+                img = images.Image(image_data=data)
+                img.resize(
+                    width=THUMB_MAX_WIDTH,
+                    height=THUMB_MAX_HEIGHT
+                )
+                thumbnail_data = img.execute_transforms()
+                thumbnail_key = key + THUMB_SUFFIX
+                memcache.set(
+                    thumbnail_key,
+                    thumbnail_data,
+                    time=EXPIRATION_TIME
+                )
+            except: #Failed to resize Image or add to memcache
+                thumbnail_key = None
+        return (key, thumbnail_key)
+
+    def handle_upload(self):
+        results = []
+        for name, fieldStorage in self.request.POST.items():
+            if type(fieldStorage) is unicode:
+                continue
+            result = {}
+            result['name'] = urllib.unquote(fieldStorage.filename)
+            result['type'] = fieldStorage.type
+            result['size'] = self.get_file_size(fieldStorage.file)
+            if self.validate(result):
+                key, thumbnail_key = self.write_blob(
+                    fieldStorage.value,
+                    result
+                )
+                if key is not None:
+                    result['url'] = self.request.host_url + '/' + key
+                    result['deleteUrl'] = result['url']
+                    result['deleteType'] = 'DELETE'
+                    if thumbnail_key is not None:
+                        result['thumbnailUrl'] = self.request.host_url +\
+                             '/' + thumbnail_key
+                else:
+                    result['error'] = 'Failed to store uploaded file.'
+            results.append(result)
+        return results
+
+    def head(self):
+        pass
+
+    def get(self):
+        self.redirect(WEBSITE)
+
+    def post(self):
+        if (self.request.get('_method') == 'DELETE'):
+            return self.delete()
+        result = {'files': self.handle_upload()}
+        s = self.json_stringify(result)
+        redirect = self.request.get('redirect')
+        if self.validate_redirect(redirect):
+            return self.redirect(str(
+                redirect.replace('%s', urllib.quote(s, ''), 1)
+            ))
+        if 'application/json' in self.request.headers.get('Accept'):
+            self.response.headers['Content-Type'] = 'application/json'
+        self.response.write(s)
+
+class FileHandler(CORSHandler):
+    def normalize(self, str):
+        return urllib.quote(urllib.unquote(str), '')
+
+    def get(self, content_type, data_hash, file_name):
+        content_type = self.normalize(content_type)
+        file_name = self.normalize(file_name)
+        key = content_type + '/' + data_hash + '/' + file_name
+        data = memcache.get(key)
+        if data is None:
+            return self.error(404)
+        # Prevent browsers from MIME-sniffing the content-type:
+        self.response.headers['X-Content-Type-Options'] = 'nosniff'
+        content_type = urllib.unquote(content_type)
+        if not IMAGE_TYPES.match(content_type):
+            # Force a download dialog for non-image types:
+            content_type = 'application/octet-stream'
+        elif file_name.endswith(THUMB_SUFFIX):
+            content_type = 'image/png'
+        self.response.headers['Content-Type'] = content_type
+        # Cache for the expiration time:
+        self.response.headers['Cache-Control'] = 'public,max-age=%d' \
+            % EXPIRATION_TIME
+        self.response.write(data)
+
+    def delete(self, content_type, data_hash, file_name):
+        content_type = self.normalize(content_type)
+        file_name = self.normalize(file_name)
+        key = content_type + '/' + data_hash + '/' + file_name
+        result = {key: memcache.delete(key)}
+        content_type = urllib.unquote(content_type)
+        if IMAGE_TYPES.match(content_type):
+            thumbnail_key = key + THUMB_SUFFIX
+            result[thumbnail_key] = memcache.delete(thumbnail_key)
+        if 'application/json' in self.request.headers.get('Accept'):
+            self.response.headers['Content-Type'] = 'application/json'
+        s = self.json_stringify(result)
+        self.response.write(s)
+
+app = webapp2.WSGIApplication(
+    [
+        ('/', UploadHandler),
+        ('/(.+)/([^/]+)/([^/]+)', FileHandler)
+    ],
+    debug=DEBUG
+)

二进制
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/static/favicon.ico


+ 2 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/gae-python/static/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow:

+ 38 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/Dockerfile

@@ -0,0 +1,38 @@
+FROM php:7.0-apache
+
+# Enable the Apache Headers module:
+RUN ln -s /etc/apache2/mods-available/headers.load \
+  /etc/apache2/mods-enabled/headers.load
+
+# Enable the Apache Rewrite module:
+RUN ln -s /etc/apache2/mods-available/rewrite.load \
+  /etc/apache2/mods-enabled/rewrite.load
+
+# Install GD, Imagick and ImageMagick as image conversion options:
+RUN DEBIAN_FRONTEND=noninteractive \
+  apt-get update && apt-get install -y --no-install-recommends \
+    libpng-dev \
+    libjpeg-dev \
+    libmagickwand-dev \
+    imagemagick \
+  && pecl install \
+    imagick \
+  && docker-php-ext-enable \
+    imagick \
+  && docker-php-ext-configure \
+    gd --with-jpeg-dir=/usr/include/ \
+  && docker-php-ext-install \
+    gd \
+  # Uninstall obsolete packages:
+  && apt-get autoremove -y \
+    libpng-dev \
+    libjpeg-dev \
+    libmagickwand-dev \
+  # Remove obsolete files:
+  && apt-get clean \
+  && rm -rf \
+    /tmp/* \
+    /usr/share/doc/* \
+    /var/cache/* \
+    /var/lib/apt/lists/* \
+    /var/tmp/*

+ 1411 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/UploadHandler.php

@@ -0,0 +1,1411 @@
+<?php
+/*
+ * jQuery File Upload Plugin PHP Class
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+class UploadHandler
+{
+
+    protected $options;
+
+    // PHP File Upload error message codes:
+    // http://php.net/manual/en/features.file-upload.errors.php
+    protected $error_messages = array(
+        1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
+        2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
+        3 => 'The uploaded file was only partially uploaded',
+        4 => 'No file was uploaded',
+        6 => 'Missing a temporary folder',
+        7 => 'Failed to write file to disk',
+        8 => 'A PHP extension stopped the file upload',
+        'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini',
+        'max_file_size' => 'File is too big',
+        'min_file_size' => 'File is too small',
+        'accept_file_types' => 'Filetype not allowed',
+        'max_number_of_files' => 'Maximum number of files exceeded',
+        'max_width' => 'Image exceeds maximum width',
+        'min_width' => 'Image requires a minimum width',
+        'max_height' => 'Image exceeds maximum height',
+        'min_height' => 'Image requires a minimum height',
+        'abort' => 'File upload aborted',
+        'image_resize' => 'Failed to resize image'
+    );
+
+    protected $image_objects = array();
+
+    public function __construct($options = null, $initialize = true, $error_messages = null) {
+        $this->response = array();
+        $this->options = array(
+            'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')),
+            'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/',
+            'upload_url' => $this->get_full_url().'/files/',
+            'input_stream' => 'php://input',
+            'user_dirs' => false,
+            'mkdir_mode' => 0755,
+            'param_name' => 'files',
+            // Set the following option to 'POST', if your server does not support
+            // DELETE requests. This is a parameter sent to the client:
+            'delete_type' => 'DELETE',
+            'access_control_allow_origin' => '*',
+            'access_control_allow_credentials' => false,
+            'access_control_allow_methods' => array(
+                'OPTIONS',
+                'HEAD',
+                'GET',
+                'POST',
+                'PUT',
+                'PATCH',
+                'DELETE'
+            ),
+            'access_control_allow_headers' => array(
+                'Content-Type',
+                'Content-Range',
+                'Content-Disposition'
+            ),
+            // By default, allow redirects to the referer protocol+host:
+            'redirect_allow_target' => '/^'.preg_quote(
+              parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME)
+                .'://'
+                .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST)
+                .'/', // Trailing slash to not match subdomains by mistake
+              '/' // preg_quote delimiter param
+            ).'/',
+            // Enable to provide file downloads via GET requests to the PHP script:
+            //     1. Set to 1 to download files via readfile method through PHP
+            //     2. Set to 2 to send a X-Sendfile header for lighttpd/Apache
+            //     3. Set to 3 to send a X-Accel-Redirect header for nginx
+            // If set to 2 or 3, adjust the upload_url option to the base path of
+            // the redirect parameter, e.g. '/files/'.
+            'download_via_php' => false,
+            // Read files in chunks to avoid memory limits when download_via_php
+            // is enabled, set to 0 to disable chunked reading of files:
+            'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB
+            // Defines which files can be displayed inline when downloaded:
+            'inline_file_types' => '/\.(gif|jpe?g|png)$/i',
+            // Defines which files (based on their names) are accepted for upload:
+            'accept_file_types' => '/.+$/i',
+            // The php.ini settings upload_max_filesize and post_max_size
+            // take precedence over the following max_file_size setting:
+            'max_file_size' => null,
+            'min_file_size' => 1,
+            // The maximum number of files for the upload directory:
+            'max_number_of_files' => null,
+            // Defines which files are handled as image files:
+            'image_file_types' => '/\.(gif|jpe?g|png)$/i',
+            // Use exif_imagetype on all files to correct file extensions:
+            'correct_image_extensions' => false,
+            // Image resolution restrictions:
+            'max_width' => null,
+            'max_height' => null,
+            'min_width' => 1,
+            'min_height' => 1,
+            // Set the following option to false to enable resumable uploads:
+            'discard_aborted_uploads' => true,
+            // Set to 0 to use the GD library to scale and orient images,
+            // set to 1 to use imagick (if installed, falls back to GD),
+            // set to 2 to use the ImageMagick convert binary directly:
+            'image_library' => 1,
+            // Uncomment the following to define an array of resource limits
+            // for imagick:
+            /*
+            'imagick_resource_limits' => array(
+                imagick::RESOURCETYPE_MAP => 32,
+                imagick::RESOURCETYPE_MEMORY => 32
+            ),
+            */
+            // Command or path for to the ImageMagick convert binary:
+            'convert_bin' => 'convert',
+            // Uncomment the following to add parameters in front of each
+            // ImageMagick convert call (the limit constraints seem only
+            // to have an effect if put in front):
+            /*
+            'convert_params' => '-limit memory 32MiB -limit map 32MiB',
+            */
+            // Command or path for to the ImageMagick identify binary:
+            'identify_bin' => 'identify',
+            'image_versions' => array(
+                // The empty image version key defines options for the original image.
+                // Keep in mind: these image manipulations are inherited by all other image versions from this point onwards. 
+                // Also note that the property 'no_cache' is not inherited, since it's not a manipulation.
+                '' => array(
+                    // Automatically rotate images based on EXIF meta data:
+                    'auto_orient' => true
+                ),
+                // You can add arrays to generate different versions.
+                // The name of the key is the name of the version (example: 'medium'). 
+                // the array contains the options to apply.
+                /*
+                'medium' => array(
+                    'max_width' => 800,
+                    'max_height' => 600
+                ),
+		*/
+                'thumbnail' => array(
+                    // Uncomment the following to use a defined directory for the thumbnails
+                    // instead of a subdirectory based on the version identifier.
+                    // Make sure that this directory doesn't allow execution of files if you
+                    // don't pose any restrictions on the type of uploaded files, e.g. by
+                    // copying the .htaccess file from the files directory for Apache:
+                    //'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/thumb/',
+                    //'upload_url' => $this->get_full_url().'/thumb/',
+                    // Uncomment the following to force the max
+                    // dimensions and e.g. create square thumbnails:
+                    // 'auto_orient' => true,
+                    // 'crop' => true,
+                    // 'jpeg_quality' => 70,
+                    // 'no_cache' => true, (there's a caching option, but this remembers thumbnail sizes from a previous action!)
+                    // 'strip' => true, (this strips EXIF tags, such as geolocation)
+                    'max_width' => 80, // either specify width, or set to 0. Then width is automatically adjusted - keeping aspect ratio to a specified max_height.
+                    'max_height' => 80 // either specify height, or set to 0. Then height is automatically adjusted - keeping aspect ratio to a specified max_width.
+                )
+            ),
+            'print_response' => true
+        );
+        if ($options) {
+            $this->options = $options + $this->options;
+        }
+        if ($error_messages) {
+            $this->error_messages = $error_messages + $this->error_messages;
+        }
+        if ($initialize) {
+            $this->initialize();
+        }
+    }
+
+    protected function initialize() {
+        switch ($this->get_server_var('REQUEST_METHOD')) {
+            case 'OPTIONS':
+            case 'HEAD':
+                $this->head();
+                break;
+            case 'GET':
+                $this->get($this->options['print_response']);
+                break;
+            case 'PATCH':
+            case 'PUT':
+            case 'POST':
+                $this->post($this->options['print_response']);
+                break;
+            case 'DELETE':
+                $this->delete($this->options['print_response']);
+                break;
+            default:
+                $this->header('HTTP/1.1 405 Method Not Allowed');
+        }
+    }
+
+    protected function get_full_url() {
+        $https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 ||
+            !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
+                strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;
+        return
+            ($https ? 'https://' : 'http://').
+            (!empty($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : '').
+            (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].
+            ($https && $_SERVER['SERVER_PORT'] === 443 ||
+            $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
+            substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
+    }
+
+    protected function get_user_id() {
+        @session_start();
+        return session_id();
+    }
+
+    protected function get_user_path() {
+        if ($this->options['user_dirs']) {
+            return $this->get_user_id().'/';
+        }
+        return '';
+    }
+
+    protected function get_upload_path($file_name = null, $version = null) {
+        $file_name = $file_name ? $file_name : '';
+        if (empty($version)) {
+            $version_path = '';
+        } else {
+            $version_dir = @$this->options['image_versions'][$version]['upload_dir'];
+            if ($version_dir) {
+                return $version_dir.$this->get_user_path().$file_name;
+            }
+            $version_path = $version.'/';
+        }
+        return $this->options['upload_dir'].$this->get_user_path()
+            .$version_path.$file_name;
+    }
+
+    protected function get_query_separator($url) {
+        return strpos($url, '?') === false ? '?' : '&';
+    }
+
+    protected function get_download_url($file_name, $version = null, $direct = false) {
+        if (!$direct && $this->options['download_via_php']) {
+            $url = $this->options['script_url']
+                .$this->get_query_separator($this->options['script_url'])
+                .$this->get_singular_param_name()
+                .'='.rawurlencode($file_name);
+            if ($version) {
+                $url .= '&version='.rawurlencode($version);
+            }
+            return $url.'&download=1';
+        }
+        if (empty($version)) {
+            $version_path = '';
+        } else {
+            $version_url = @$this->options['image_versions'][$version]['upload_url'];
+            if ($version_url) {
+                return $version_url.$this->get_user_path().rawurlencode($file_name);
+            }
+            $version_path = rawurlencode($version).'/';
+        }
+        return $this->options['upload_url'].$this->get_user_path()
+            .$version_path.rawurlencode($file_name);
+    }
+
+    protected function set_additional_file_properties($file) {
+        $file->deleteUrl = $this->options['script_url']
+            .$this->get_query_separator($this->options['script_url'])
+            .$this->get_singular_param_name()
+            .'='.rawurlencode($file->name);
+        $file->deleteType = $this->options['delete_type'];
+        if ($file->deleteType !== 'DELETE') {
+            $file->deleteUrl .= '&_method=DELETE';
+        }
+        if ($this->options['access_control_allow_credentials']) {
+            $file->deleteWithCredentials = true;
+        }
+    }
+
+    // Fix for overflowing signed 32 bit integers,
+    // works for sizes up to 2^32-1 bytes (4 GiB - 1):
+    protected function fix_integer_overflow($size) {
+        if ($size < 0) {
+            $size += 2.0 * (PHP_INT_MAX + 1);
+        }
+        return $size;
+    }
+
+    protected function get_file_size($file_path, $clear_stat_cache = false) {
+        if ($clear_stat_cache) {
+            if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+                clearstatcache(true, $file_path);
+            } else {
+                clearstatcache();
+            }
+        }
+        return $this->fix_integer_overflow(filesize($file_path));
+    }
+
+    protected function is_valid_file_object($file_name) {
+        $file_path = $this->get_upload_path($file_name);
+        if (is_file($file_path) && $file_name[0] !== '.') {
+            return true;
+        }
+        return false;
+    }
+
+    protected function get_file_object($file_name) {
+        if ($this->is_valid_file_object($file_name)) {
+            $file = new \stdClass();
+            $file->name = $file_name;
+            $file->size = $this->get_file_size(
+                $this->get_upload_path($file_name)
+            );
+            $file->url = $this->get_download_url($file->name);
+            foreach ($this->options['image_versions'] as $version => $options) {
+                if (!empty($version)) {
+                    if (is_file($this->get_upload_path($file_name, $version))) {
+                        $file->{$version.'Url'} = $this->get_download_url(
+                            $file->name,
+                            $version
+                        );
+                    }
+                }
+            }
+            $this->set_additional_file_properties($file);
+            return $file;
+        }
+        return null;
+    }
+
+    protected function get_file_objects($iteration_method = 'get_file_object') {
+        $upload_dir = $this->get_upload_path();
+        if (!is_dir($upload_dir)) {
+            return array();
+        }
+        return array_values(array_filter(array_map(
+            array($this, $iteration_method),
+            scandir($upload_dir)
+        )));
+    }
+
+    protected function count_file_objects() {
+        return count($this->get_file_objects('is_valid_file_object'));
+    }
+
+    protected function get_error_message($error) {
+        return isset($this->error_messages[$error]) ?
+            $this->error_messages[$error] : $error;
+    }
+
+    public function get_config_bytes($val) {
+        $val = trim($val);
+        $last = strtolower($val[strlen($val)-1]);
+        $val = (int)$val;
+        switch ($last) {
+            case 'g':
+                $val *= 1024;
+            case 'm':
+                $val *= 1024;
+            case 'k':
+                $val *= 1024;
+        }
+        return $this->fix_integer_overflow($val);
+    }
+
+    protected function validate($uploaded_file, $file, $error, $index) {
+        if ($error) {
+            $file->error = $this->get_error_message($error);
+            return false;
+        }
+        $content_length = $this->fix_integer_overflow(
+            (int)$this->get_server_var('CONTENT_LENGTH')
+        );
+        $post_max_size = $this->get_config_bytes(ini_get('post_max_size'));
+        if ($post_max_size && ($content_length > $post_max_size)) {
+            $file->error = $this->get_error_message('post_max_size');
+            return false;
+        }
+        if (!preg_match($this->options['accept_file_types'], $file->name)) {
+            $file->error = $this->get_error_message('accept_file_types');
+            return false;
+        }
+        if ($uploaded_file && is_uploaded_file($uploaded_file)) {
+            $file_size = $this->get_file_size($uploaded_file);
+        } else {
+            $file_size = $content_length;
+        }
+        if ($this->options['max_file_size'] && (
+                $file_size > $this->options['max_file_size'] ||
+                $file->size > $this->options['max_file_size'])
+            ) {
+            $file->error = $this->get_error_message('max_file_size');
+            return false;
+        }
+        if ($this->options['min_file_size'] &&
+            $file_size < $this->options['min_file_size']) {
+            $file->error = $this->get_error_message('min_file_size');
+            return false;
+        }
+        if (is_int($this->options['max_number_of_files']) &&
+                ($this->count_file_objects() >= $this->options['max_number_of_files']) &&
+                // Ignore additional chunks of existing files:
+                !is_file($this->get_upload_path($file->name))) {
+            $file->error = $this->get_error_message('max_number_of_files');
+            return false;
+        }
+        $max_width = @$this->options['max_width'];
+        $max_height = @$this->options['max_height'];
+        $min_width = @$this->options['min_width'];
+        $min_height = @$this->options['min_height'];
+        if (($max_width || $max_height || $min_width || $min_height)
+           && preg_match($this->options['image_file_types'], $file->name)) {
+            list($img_width, $img_height) = $this->get_image_size($uploaded_file);
+
+            // If we are auto rotating the image by default, do the checks on
+            // the correct orientation
+            if (
+                @$this->options['image_versions']['']['auto_orient'] &&
+                function_exists('exif_read_data') &&
+                ($exif = @exif_read_data($uploaded_file)) &&
+                (((int) @$exif['Orientation']) >= 5)
+            ) {
+                $tmp = $img_width;
+                $img_width = $img_height;
+                $img_height = $tmp;
+                unset($tmp);
+            }
+
+        }
+        if (!empty($img_width)) {
+            if ($max_width && $img_width > $max_width) {
+                $file->error = $this->get_error_message('max_width');
+                return false;
+            }
+            if ($max_height && $img_height > $max_height) {
+                $file->error = $this->get_error_message('max_height');
+                return false;
+            }
+            if ($min_width && $img_width < $min_width) {
+                $file->error = $this->get_error_message('min_width');
+                return false;
+            }
+            if ($min_height && $img_height < $min_height) {
+                $file->error = $this->get_error_message('min_height');
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected function upcount_name_callback($matches) {
+        $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1;
+        $ext = isset($matches[2]) ? $matches[2] : '';
+        return ' ('.$index.')'.$ext;
+    }
+
+    protected function upcount_name($name) {
+        return preg_replace_callback(
+            '/(?:(?: \(([\d]+)\))?(\.[^.]+))?$/',
+            array($this, 'upcount_name_callback'),
+            $name,
+            1
+        );
+    }
+
+    protected function get_unique_filename($file_path, $name, $size, $type, $error,
+            $index, $content_range) {
+        while(is_dir($this->get_upload_path($name))) {
+            $name = $this->upcount_name($name);
+        }
+        // Keep an existing filename if this is part of a chunked upload:
+        $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]);
+        while (is_file($this->get_upload_path($name))) {
+            if ($uploaded_bytes === $this->get_file_size(
+                    $this->get_upload_path($name))) {
+                break;
+            }
+            $name = $this->upcount_name($name);
+        }
+        return $name;
+    }
+
+    protected function fix_file_extension($file_path, $name, $size, $type, $error,
+            $index, $content_range) {
+        // Add missing file extension for known image types:
+        if (strpos($name, '.') === false &&
+                preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
+            $name .= '.'.$matches[1];
+        }
+        if ($this->options['correct_image_extensions'] &&
+                function_exists('exif_imagetype')) {
+            switch (@exif_imagetype($file_path)){
+                case IMAGETYPE_JPEG:
+                    $extensions = array('jpg', 'jpeg');
+                    break;
+                case IMAGETYPE_PNG:
+                    $extensions = array('png');
+                    break;
+                case IMAGETYPE_GIF:
+                    $extensions = array('gif');
+                    break;
+            }
+            // Adjust incorrect image file extensions:
+            if (!empty($extensions)) {
+                $parts = explode('.', $name);
+                $extIndex = count($parts) - 1;
+                $ext = strtolower(@$parts[$extIndex]);
+                if (!in_array($ext, $extensions)) {
+                    $parts[$extIndex] = $extensions[0];
+                    $name = implode('.', $parts);
+                }
+            }
+        }
+        return $name;
+    }
+
+    protected function trim_file_name($file_path, $name, $size, $type, $error,
+            $index, $content_range) {
+        // Remove path information and dots around the filename, to prevent uploading
+        // into different directories or replacing hidden system files.
+        // Also remove control characters and spaces (\x00..\x20) around the filename:
+        $name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
+        // Use a timestamp for empty filenames:
+        if (!$name) {
+            $name = str_replace('.', '-', microtime(true));
+        }
+        return $name;
+    }
+
+    protected function get_file_name($file_path, $name, $size, $type, $error,
+            $index, $content_range) {
+        $name = $this->trim_file_name($file_path, $name, $size, $type, $error,
+            $index, $content_range);
+        return $this->get_unique_filename(
+            $file_path,
+            $this->fix_file_extension($file_path, $name, $size, $type, $error,
+                $index, $content_range),
+            $size,
+            $type,
+            $error,
+            $index,
+            $content_range
+        );
+    }
+
+    protected function get_scaled_image_file_paths($file_name, $version) {
+        $file_path = $this->get_upload_path($file_name);
+        if (!empty($version)) {
+            $version_dir = $this->get_upload_path(null, $version);
+            if (!is_dir($version_dir)) {
+                mkdir($version_dir, $this->options['mkdir_mode'], true);
+            }
+            $new_file_path = $version_dir.'/'.$file_name;
+        } else {
+            $new_file_path = $file_path;
+        }
+        return array($file_path, $new_file_path);
+    }
+
+    protected function gd_get_image_object($file_path, $func, $no_cache = false) {
+        if (empty($this->image_objects[$file_path]) || $no_cache) {
+            $this->gd_destroy_image_object($file_path);
+            $this->image_objects[$file_path] = $func($file_path);
+        }
+        return $this->image_objects[$file_path];
+    }
+
+    protected function gd_set_image_object($file_path, $image) {
+        $this->gd_destroy_image_object($file_path);
+        $this->image_objects[$file_path] = $image;
+    }
+
+    protected function gd_destroy_image_object($file_path) {
+        $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ;
+        return $image && imagedestroy($image);
+    }
+
+    protected function gd_imageflip($image, $mode) {
+        if (function_exists('imageflip')) {
+            return imageflip($image, $mode);
+        }
+        $new_width = $src_width = imagesx($image);
+        $new_height = $src_height = imagesy($image);
+        $new_img = imagecreatetruecolor($new_width, $new_height);
+        $src_x = 0;
+        $src_y = 0;
+        switch ($mode) {
+            case '1': // flip on the horizontal axis
+                $src_y = $new_height - 1;
+                $src_height = -$new_height;
+                break;
+            case '2': // flip on the vertical axis
+                $src_x  = $new_width - 1;
+                $src_width = -$new_width;
+                break;
+            case '3': // flip on both axes
+                $src_y = $new_height - 1;
+                $src_height = -$new_height;
+                $src_x  = $new_width - 1;
+                $src_width = -$new_width;
+                break;
+            default:
+                return $image;
+        }
+        imagecopyresampled(
+            $new_img,
+            $image,
+            0,
+            0,
+            $src_x,
+            $src_y,
+            $new_width,
+            $new_height,
+            $src_width,
+            $src_height
+        );
+        return $new_img;
+    }
+
+    protected function gd_orient_image($file_path, $src_img) {
+        if (!function_exists('exif_read_data')) {
+            return false;
+        }
+        $exif = @exif_read_data($file_path);
+        if ($exif === false) {
+            return false;
+        }
+        $orientation = (int)@$exif['Orientation'];
+        if ($orientation < 2 || $orientation > 8) {
+            return false;
+        }
+        switch ($orientation) {
+            case 2:
+                $new_img = $this->gd_imageflip(
+                    $src_img,
+                    defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2
+                );
+                break;
+            case 3:
+                $new_img = imagerotate($src_img, 180, 0);
+                break;
+            case 4:
+                $new_img = $this->gd_imageflip(
+                    $src_img,
+                    defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1
+                );
+                break;
+            case 5:
+                $tmp_img = $this->gd_imageflip(
+                    $src_img,
+                    defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1
+                );
+                $new_img = imagerotate($tmp_img, 270, 0);
+                imagedestroy($tmp_img);
+                break;
+            case 6:
+                $new_img = imagerotate($src_img, 270, 0);
+                break;
+            case 7:
+                $tmp_img = $this->gd_imageflip(
+                    $src_img,
+                    defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2
+                );
+                $new_img = imagerotate($tmp_img, 270, 0);
+                imagedestroy($tmp_img);
+                break;
+            case 8:
+                $new_img = imagerotate($src_img, 90, 0);
+                break;
+            default:
+                return false;
+        }
+        $this->gd_set_image_object($file_path, $new_img);
+        return true;
+    }
+
+    protected function gd_create_scaled_image($file_name, $version, $options) {
+        if (!function_exists('imagecreatetruecolor')) {
+            error_log('Function not found: imagecreatetruecolor');
+            return false;
+        }
+        list($file_path, $new_file_path) =
+            $this->get_scaled_image_file_paths($file_name, $version);
+        $type = strtolower(substr(strrchr($file_name, '.'), 1));
+        switch ($type) {
+            case 'jpg':
+            case 'jpeg':
+                $src_func = 'imagecreatefromjpeg';
+                $write_func = 'imagejpeg';
+                $image_quality = isset($options['jpeg_quality']) ?
+                    $options['jpeg_quality'] : 75;
+                break;
+            case 'gif':
+                $src_func = 'imagecreatefromgif';
+                $write_func = 'imagegif';
+                $image_quality = null;
+                break;
+            case 'png':
+                $src_func = 'imagecreatefrompng';
+                $write_func = 'imagepng';
+                $image_quality = isset($options['png_quality']) ?
+                    $options['png_quality'] : 9;
+                break;
+            default:
+                return false;
+        }
+        $src_img = $this->gd_get_image_object(
+            $file_path,
+            $src_func,
+            !empty($options['no_cache'])
+        );
+        $image_oriented = false;
+        if (!empty($options['auto_orient']) && $this->gd_orient_image(
+                $file_path,
+                $src_img
+            )) {
+            $image_oriented = true;
+            $src_img = $this->gd_get_image_object(
+                $file_path,
+                $src_func
+            );
+        }
+        $max_width = $img_width = imagesx($src_img);
+        $max_height = $img_height = imagesy($src_img);
+        if (!empty($options['max_width'])) {
+            $max_width = $options['max_width'];
+        }
+        if (!empty($options['max_height'])) {
+            $max_height = $options['max_height'];
+        }
+        $scale = min(
+            $max_width / $img_width,
+            $max_height / $img_height
+        );
+        if ($scale >= 1) {
+            if ($image_oriented) {
+                return $write_func($src_img, $new_file_path, $image_quality);
+            }
+            if ($file_path !== $new_file_path) {
+                return copy($file_path, $new_file_path);
+            }
+            return true;
+        }
+        if (empty($options['crop'])) {
+            $new_width = $img_width * $scale;
+            $new_height = $img_height * $scale;
+            $dst_x = 0;
+            $dst_y = 0;
+            $new_img = imagecreatetruecolor($new_width, $new_height);
+        } else {
+            if (($img_width / $img_height) >= ($max_width / $max_height)) {
+                $new_width = $img_width / ($img_height / $max_height);
+                $new_height = $max_height;
+            } else {
+                $new_width = $max_width;
+                $new_height = $img_height / ($img_width / $max_width);
+            }
+            $dst_x = 0 - ($new_width - $max_width) / 2;
+            $dst_y = 0 - ($new_height - $max_height) / 2;
+            $new_img = imagecreatetruecolor($max_width, $max_height);
+        }
+        // Handle transparency in GIF and PNG images:
+        switch ($type) {
+            case 'gif':
+            case 'png':
+                imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0));
+            case 'png':
+                imagealphablending($new_img, false);
+                imagesavealpha($new_img, true);
+                break;
+        }
+        $success = imagecopyresampled(
+            $new_img,
+            $src_img,
+            $dst_x,
+            $dst_y,
+            0,
+            0,
+            $new_width,
+            $new_height,
+            $img_width,
+            $img_height
+        ) && $write_func($new_img, $new_file_path, $image_quality);
+        $this->gd_set_image_object($file_path, $new_img);
+        return $success;
+    }
+
+    protected function imagick_get_image_object($file_path, $no_cache = false) {
+        if (empty($this->image_objects[$file_path]) || $no_cache) {
+            $this->imagick_destroy_image_object($file_path);
+            $image = new \Imagick();
+            if (!empty($this->options['imagick_resource_limits'])) {
+                foreach ($this->options['imagick_resource_limits'] as $type => $limit) {
+                    $image->setResourceLimit($type, $limit);
+                }
+            }
+            $image->readImage($file_path);
+            $this->image_objects[$file_path] = $image;
+        }
+        return $this->image_objects[$file_path];
+    }
+
+    protected function imagick_set_image_object($file_path, $image) {
+        $this->imagick_destroy_image_object($file_path);
+        $this->image_objects[$file_path] = $image;
+    }
+
+    protected function imagick_destroy_image_object($file_path) {
+        $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ;
+        return $image && $image->destroy();
+    }
+
+    protected function imagick_orient_image($image) {
+        $orientation = $image->getImageOrientation();
+        $background = new \ImagickPixel('none');
+        switch ($orientation) {
+            case \imagick::ORIENTATION_TOPRIGHT: // 2
+                $image->flopImage(); // horizontal flop around y-axis
+                break;
+            case \imagick::ORIENTATION_BOTTOMRIGHT: // 3
+                $image->rotateImage($background, 180);
+                break;
+            case \imagick::ORIENTATION_BOTTOMLEFT: // 4
+                $image->flipImage(); // vertical flip around x-axis
+                break;
+            case \imagick::ORIENTATION_LEFTTOP: // 5
+                $image->flopImage(); // horizontal flop around y-axis
+                $image->rotateImage($background, 270);
+                break;
+            case \imagick::ORIENTATION_RIGHTTOP: // 6
+                $image->rotateImage($background, 90);
+                break;
+            case \imagick::ORIENTATION_RIGHTBOTTOM: // 7
+                $image->flipImage(); // vertical flip around x-axis
+                $image->rotateImage($background, 270);
+                break;
+            case \imagick::ORIENTATION_LEFTBOTTOM: // 8
+                $image->rotateImage($background, 270);
+                break;
+            default:
+                return false;
+        }
+        $image->setImageOrientation(\imagick::ORIENTATION_TOPLEFT); // 1
+        return true;
+    }
+
+    protected function imagick_create_scaled_image($file_name, $version, $options) {
+        list($file_path, $new_file_path) =
+            $this->get_scaled_image_file_paths($file_name, $version);
+        $image = $this->imagick_get_image_object(
+            $file_path,
+            !empty($options['crop']) || !empty($options['no_cache'])
+        );
+        if ($image->getImageFormat() === 'GIF') {
+            // Handle animated GIFs:
+            $images = $image->coalesceImages();
+            foreach ($images as $frame) {
+                $image = $frame;
+                $this->imagick_set_image_object($file_name, $image);
+                break;
+            }
+        }
+        $image_oriented = false;
+        if (!empty($options['auto_orient'])) {
+            $image_oriented = $this->imagick_orient_image($image);
+        } 
+	    
+        $image_resize = false; 
+        $new_width = $max_width = $img_width = $image->getImageWidth();
+        $new_height = $max_height = $img_height = $image->getImageHeight(); 
+		  
+        // use isset(). User might be setting max_width = 0 (auto in regular resizing). Value 0 would be considered empty when you use empty()
+        if (isset($options['max_width'])) {
+            $image_resize = true; 
+            $new_width = $max_width = $options['max_width']; 
+        }
+        if (isset($options['max_height'])) {
+            $image_resize = true;
+            $new_height = $max_height = $options['max_height'];
+        }
+        
+        $image_strip = (isset($options['strip']) ? $options['strip'] : false);
+ 
+        if ( !$image_oriented && ($max_width >= $img_width) && ($max_height >= $img_height) && !$image_strip && empty($options["jpeg_quality"]) ) {        
+            if ($file_path !== $new_file_path) {
+                return copy($file_path, $new_file_path);
+            }
+            return true;
+        }
+        $crop = (isset($options['crop']) ? $options['crop'] : false);
+        
+        if ($crop) {
+            $x = 0;
+            $y = 0;
+            if (($img_width / $img_height) >= ($max_width / $max_height)) {
+                $new_width = 0; // Enables proportional scaling based on max_height
+                $x = ($img_width / ($img_height / $max_height) - $max_width) / 2;
+            } else {
+                $new_height = 0; // Enables proportional scaling based on max_width
+                $y = ($img_height / ($img_width / $max_width) - $max_height) / 2;
+            }
+        }
+        $success = $image->resizeImage(
+            $new_width,
+            $new_height,
+            isset($options['filter']) ? $options['filter'] : \imagick::FILTER_LANCZOS,
+            isset($options['blur']) ? $options['blur'] : 1,
+            $new_width && $new_height // fit image into constraints if not to be cropped
+        );
+        if ($success && $crop) {
+            $success = $image->cropImage(
+                $max_width,
+                $max_height,
+                $x,
+                $y
+            );
+            if ($success) {
+                $success = $image->setImagePage($max_width, $max_height, 0, 0);
+            }
+        }
+        $type = strtolower(substr(strrchr($file_name, '.'), 1));
+        switch ($type) {
+            case 'jpg':
+            case 'jpeg':
+                if (!empty($options['jpeg_quality'])) {
+                    $image->setImageCompression(\imagick::COMPRESSION_JPEG);
+                    $image->setImageCompressionQuality($options['jpeg_quality']);
+                }
+                break;
+        }
+        if ( $image_strip ) {
+            $image->stripImage();
+        }
+        return $success && $image->writeImage($new_file_path);
+    }
+
+    protected function imagemagick_create_scaled_image($file_name, $version, $options) {
+        list($file_path, $new_file_path) =
+            $this->get_scaled_image_file_paths($file_name, $version);
+        $resize = @$options['max_width']
+            .(empty($options['max_height']) ? '' : 'X'.$options['max_height']);
+        if (!$resize && empty($options['auto_orient'])) {
+            if ($file_path !== $new_file_path) {
+                return copy($file_path, $new_file_path);
+            }
+            return true;
+        }
+        $cmd = $this->options['convert_bin'];
+        if (!empty($this->options['convert_params'])) {
+            $cmd .= ' '.$this->options['convert_params'];
+        }
+        $cmd .= ' '.escapeshellarg($file_path);
+        if (!empty($options['auto_orient'])) {
+            $cmd .= ' -auto-orient';
+        }
+        if ($resize) {
+            // Handle animated GIFs:
+            $cmd .= ' -coalesce';
+            if (empty($options['crop'])) {
+                $cmd .= ' -resize '.escapeshellarg($resize.'>');
+            } else {
+                $cmd .= ' -resize '.escapeshellarg($resize.'^');
+                $cmd .= ' -gravity center';
+                $cmd .= ' -crop '.escapeshellarg($resize.'+0+0');
+            }
+            // Make sure the page dimensions are correct (fixes offsets of animated GIFs):
+            $cmd .= ' +repage';
+        }
+        if (!empty($options['convert_params'])) {
+            $cmd .= ' '.$options['convert_params'];
+        }
+        $cmd .= ' '.escapeshellarg($new_file_path);
+        exec($cmd, $output, $error);
+        if ($error) {
+            error_log(implode('\n', $output));
+            return false;
+        }
+        return true;
+    }
+
+    protected function get_image_size($file_path) {
+        if ($this->options['image_library']) {
+            if (extension_loaded('imagick')) {
+                $image = new \Imagick();
+                try {
+                    if (@$image->pingImage($file_path)) {
+                        $dimensions = array($image->getImageWidth(), $image->getImageHeight());
+                        $image->destroy();
+                        return $dimensions;
+                    }
+                    return false;
+                } catch (\Exception $e) {
+                    error_log($e->getMessage());
+                }
+            }
+            if ($this->options['image_library'] === 2) {
+                $cmd = $this->options['identify_bin'];
+                $cmd .= ' -ping '.escapeshellarg($file_path);
+                exec($cmd, $output, $error);
+                if (!$error && !empty($output)) {
+                    // image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000
+                    $infos = preg_split('/\s+/', substr($output[0], strlen($file_path)));
+                    $dimensions = preg_split('/x/', $infos[2]);
+                    return $dimensions;
+                }
+                return false;
+            }
+        }
+        if (!function_exists('getimagesize')) {
+            error_log('Function not found: getimagesize');
+            return false;
+        }
+        return @getimagesize($file_path);
+    }
+
+    protected function create_scaled_image($file_name, $version, $options) {
+        if ($this->options['image_library'] === 2) {
+            return $this->imagemagick_create_scaled_image($file_name, $version, $options);
+        }
+        if ($this->options['image_library'] && extension_loaded('imagick')) {
+            return $this->imagick_create_scaled_image($file_name, $version, $options);
+        }
+        return $this->gd_create_scaled_image($file_name, $version, $options);
+    }
+
+    protected function destroy_image_object($file_path) {
+        if ($this->options['image_library'] && extension_loaded('imagick')) {
+            return $this->imagick_destroy_image_object($file_path);
+        }
+    }
+
+    protected function is_valid_image_file($file_path) {
+        if (!preg_match($this->options['image_file_types'], $file_path)) {
+            return false;
+        }
+        if (function_exists('exif_imagetype')) {
+            return @exif_imagetype($file_path);
+        }
+        $image_info = $this->get_image_size($file_path);
+        return $image_info && $image_info[0] && $image_info[1];
+    }
+
+    protected function handle_image_file($file_path, $file) {
+        $failed_versions = array();
+        foreach ($this->options['image_versions'] as $version => $options) {
+            if ($this->create_scaled_image($file->name, $version, $options)) {
+                if (!empty($version)) {
+                    $file->{$version.'Url'} = $this->get_download_url(
+                        $file->name,
+                        $version
+                    );
+                } else {
+                    $file->size = $this->get_file_size($file_path, true);
+                }
+            } else {
+                $failed_versions[] = $version ? $version : 'original';
+            }
+        }
+        if (count($failed_versions)) {
+            $file->error = $this->get_error_message('image_resize')
+                    .' ('.implode($failed_versions, ', ').')';
+        }
+        // Free memory:
+        $this->destroy_image_object($file_path);
+    }
+
+    protected function handle_file_upload($uploaded_file, $name, $size, $type, $error,
+            $index = null, $content_range = null) {
+        $file = new \stdClass();
+        $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error,
+            $index, $content_range);
+        $file->size = $this->fix_integer_overflow((int)$size);
+        $file->type = $type;
+        if ($this->validate($uploaded_file, $file, $error, $index)) {
+            $this->handle_form_data($file, $index);
+            $upload_dir = $this->get_upload_path();
+            if (!is_dir($upload_dir)) {
+                mkdir($upload_dir, $this->options['mkdir_mode'], true);
+            }
+            $file_path = $this->get_upload_path($file->name);
+            $append_file = $content_range && is_file($file_path) &&
+                $file->size > $this->get_file_size($file_path);
+            if ($uploaded_file && is_uploaded_file($uploaded_file)) {
+                // multipart/formdata uploads (POST method uploads)
+                if ($append_file) {
+                    file_put_contents(
+                        $file_path,
+                        fopen($uploaded_file, 'r'),
+                        FILE_APPEND
+                    );
+                } else {
+                    move_uploaded_file($uploaded_file, $file_path);
+                }
+            } else {
+                // Non-multipart uploads (PUT method support)
+                file_put_contents(
+                    $file_path,
+                    fopen($this->options['input_stream'], 'r'),
+                    $append_file ? FILE_APPEND : 0
+                );
+            }
+            $file_size = $this->get_file_size($file_path, $append_file);
+            if ($file_size === $file->size) {
+                $file->url = $this->get_download_url($file->name);
+                if ($this->is_valid_image_file($file_path)) {
+                    $this->handle_image_file($file_path, $file);
+                }
+            } else {
+                $file->size = $file_size;
+                if (!$content_range && $this->options['discard_aborted_uploads']) {
+                    unlink($file_path);
+                    $file->error = $this->get_error_message('abort');
+                }
+            }
+            $this->set_additional_file_properties($file);
+        }
+        return $file;
+    }
+
+    protected function readfile($file_path) {
+        $file_size = $this->get_file_size($file_path);
+        $chunk_size = $this->options['readfile_chunk_size'];
+        if ($chunk_size && $file_size > $chunk_size) {
+            $handle = fopen($file_path, 'rb');
+            while (!feof($handle)) {
+                echo fread($handle, $chunk_size);
+                @ob_flush();
+                @flush();
+            }
+            fclose($handle);
+            return $file_size;
+        }
+        return readfile($file_path);
+    }
+
+    protected function body($str) {
+        echo $str;
+    }
+
+    protected function header($str) {
+        header($str);
+    }
+
+    protected function get_upload_data($id) {
+        return @$_FILES[$id];
+    }
+
+    protected function get_post_param($id) {
+        return @$_POST[$id];
+    }
+
+    protected function get_query_param($id) {
+        return @$_GET[$id];
+    }
+
+    protected function get_server_var($id) {
+        return @$_SERVER[$id];
+    }
+
+    protected function handle_form_data($file, $index) {
+        // Handle form data, e.g. $_POST['description'][$index]
+    }
+
+    protected function get_version_param() {
+        return $this->basename(stripslashes($this->get_query_param('version')));
+    }
+
+    protected function get_singular_param_name() {
+        return substr($this->options['param_name'], 0, -1);
+    }
+
+    protected function get_file_name_param() {
+        $name = $this->get_singular_param_name();
+        return $this->basename(stripslashes($this->get_query_param($name)));
+    }
+
+    protected function get_file_names_params() {
+        $params = $this->get_query_param($this->options['param_name']);
+        if (!$params) {
+            return null;
+        }
+        foreach ($params as $key => $value) {
+            $params[$key] = $this->basename(stripslashes($value));
+        }
+        return $params;
+    }
+
+    protected function get_file_type($file_path) {
+        switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) {
+            case 'jpeg':
+            case 'jpg':
+                return 'image/jpeg';
+            case 'png':
+                return 'image/png';
+            case 'gif':
+                return 'image/gif';
+            default:
+                return '';
+        }
+    }
+
+    protected function download() {
+        switch ($this->options['download_via_php']) {
+            case 1:
+                $redirect_header = null;
+                break;
+            case 2:
+                $redirect_header = 'X-Sendfile';
+                break;
+            case 3:
+                $redirect_header = 'X-Accel-Redirect';
+                break;
+            default:
+                return $this->header('HTTP/1.1 403 Forbidden');
+        }
+        $file_name = $this->get_file_name_param();
+        if (!$this->is_valid_file_object($file_name)) {
+            return $this->header('HTTP/1.1 404 Not Found');
+        }
+        if ($redirect_header) {
+            return $this->header(
+                $redirect_header.': '.$this->get_download_url(
+                    $file_name,
+                    $this->get_version_param(),
+                    true
+                )
+            );
+        }
+        $file_path = $this->get_upload_path($file_name, $this->get_version_param());
+        // Prevent browsers from MIME-sniffing the content-type:
+        $this->header('X-Content-Type-Options: nosniff');
+        if (!preg_match($this->options['inline_file_types'], $file_name)) {
+            $this->header('Content-Type: application/octet-stream');
+            $this->header('Content-Disposition: attachment; filename="'.$file_name.'"');
+        } else {
+            $this->header('Content-Type: '.$this->get_file_type($file_path));
+            $this->header('Content-Disposition: inline; filename="'.$file_name.'"');
+        }
+        $this->header('Content-Length: '.$this->get_file_size($file_path));
+        $this->header('Last-Modified: '.gmdate('D, d M Y H:i:s T', filemtime($file_path)));
+        $this->readfile($file_path);
+    }
+
+    protected function send_content_type_header() {
+        $this->header('Vary: Accept');
+        if (strpos($this->get_server_var('HTTP_ACCEPT'), 'application/json') !== false) {
+            $this->header('Content-type: application/json');
+        } else {
+            $this->header('Content-type: text/plain');
+        }
+    }
+
+    protected function send_access_control_headers() {
+        $this->header('Access-Control-Allow-Origin: '.$this->options['access_control_allow_origin']);
+        $this->header('Access-Control-Allow-Credentials: '
+            .($this->options['access_control_allow_credentials'] ? 'true' : 'false'));
+        $this->header('Access-Control-Allow-Methods: '
+            .implode(', ', $this->options['access_control_allow_methods']));
+        $this->header('Access-Control-Allow-Headers: '
+            .implode(', ', $this->options['access_control_allow_headers']));
+    }
+
+    public function generate_response($content, $print_response = true) {
+        $this->response = $content;
+        if ($print_response) {
+            $json = json_encode($content);
+            $redirect = stripslashes($this->get_post_param('redirect'));
+            if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) {
+                $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
+                return;
+            }
+            $this->head();
+            if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
+                $files = isset($content[$this->options['param_name']]) ?
+                    $content[$this->options['param_name']] : null;
+                if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) {
+                    $this->header('Range: 0-'.(
+                        $this->fix_integer_overflow((int)$files[0]->size) - 1
+                    ));
+                }
+            }
+            $this->body($json);
+        }
+        return $content;
+    }
+
+    public function get_response () {
+        return $this->response;
+    }
+
+    public function head() {
+        $this->header('Pragma: no-cache');
+        $this->header('Cache-Control: no-store, no-cache, must-revalidate');
+        $this->header('Content-Disposition: inline; filename="files.json"');
+        // Prevent Internet Explorer from MIME-sniffing the content-type:
+        $this->header('X-Content-Type-Options: nosniff');
+        if ($this->options['access_control_allow_origin']) {
+            $this->send_access_control_headers();
+        }
+        $this->send_content_type_header();
+    }
+
+    public function get($print_response = true) {
+        if ($print_response && $this->get_query_param('download')) {
+            return $this->download();
+        }
+        $file_name = $this->get_file_name_param();
+        if ($file_name) {
+            $response = array(
+                $this->get_singular_param_name() => $this->get_file_object($file_name)
+            );
+        } else {
+            $response = array(
+                $this->options['param_name'] => $this->get_file_objects()
+            );
+        }
+        return $this->generate_response($response, $print_response);
+    }
+
+    public function post($print_response = true) {
+        if ($this->get_query_param('_method') === 'DELETE') {
+            return $this->delete($print_response);
+        }
+        $upload = $this->get_upload_data($this->options['param_name']);
+        // Parse the Content-Disposition header, if available:
+        $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION');
+        $file_name = $content_disposition_header ?
+            rawurldecode(preg_replace(
+                '/(^[^"]+")|("$)/',
+                '',
+                $content_disposition_header
+            )) : null;
+        // Parse the Content-Range header, which has the following form:
+        // Content-Range: bytes 0-524287/2000000
+        $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE');
+        $content_range = $content_range_header ?
+            preg_split('/[^0-9]+/', $content_range_header) : null;
+        $size =  $content_range ? $content_range[3] : null;
+        $files = array();
+        if ($upload) {
+            if (is_array($upload['tmp_name'])) {
+                // param_name is an array identifier like "files[]",
+                // $upload is a multi-dimensional array:
+                foreach ($upload['tmp_name'] as $index => $value) {
+                    $files[] = $this->handle_file_upload(
+                        $upload['tmp_name'][$index],
+                        $file_name ? $file_name : $upload['name'][$index],
+                        $size ? $size : $upload['size'][$index],
+                        $upload['type'][$index],
+                        $upload['error'][$index],
+                        $index,
+                        $content_range
+                    );
+                }
+            } else {
+                // param_name is a single object identifier like "file",
+                // $upload is a one-dimensional array:
+                $files[] = $this->handle_file_upload(
+                    isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
+                    $file_name ? $file_name : (isset($upload['name']) ?
+                            $upload['name'] : null),
+                    $size ? $size : (isset($upload['size']) ?
+                            $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
+                    isset($upload['type']) ?
+                            $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
+                    isset($upload['error']) ? $upload['error'] : null,
+                    null,
+                    $content_range
+                );
+            }
+        }
+        $response = array($this->options['param_name'] => $files);
+        return $this->generate_response($response, $print_response);
+    }
+
+    public function delete($print_response = true) {
+        $file_names = $this->get_file_names_params();
+        if (empty($file_names)) {
+            $file_names = array($this->get_file_name_param());
+        }
+        $response = array();
+        foreach ($file_names as $file_name) {
+            $file_path = $this->get_upload_path($file_name);
+            $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
+            if ($success) {
+                foreach ($this->options['image_versions'] as $version => $options) {
+                    if (!empty($version)) {
+                        $file = $this->get_upload_path($file_name, $version);
+                        if (is_file($file)) {
+                            unlink($file);
+                        }
+                    }
+                }
+            }
+            $response[$file_name] = $success;
+        }
+        return $this->generate_response($response, $print_response);
+    }
+
+    protected function basename($filepath, $suffix = null) {
+        $splited = preg_split('/\//', rtrim ($filepath, '/ '));
+        return substr(basename('X'.$splited[count($splited)-1], $suffix), 1);
+    }
+}

+ 6 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/docker-compose.yml

@@ -0,0 +1,6 @@
+apache:
+  build: ./
+  ports:
+    - "80:80"
+  volumes:
+    - "../../:/var/www/html"

+ 15 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/server/php/index.php

@@ -0,0 +1,15 @@
+<?php
+/*
+ * jQuery File Upload Plugin PHP Example
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+error_reporting(E_ALL | E_STRICT);
+require('UploadHandler.php');
+$upload_handler = new UploadHandler();

+ 172 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/test/index.html

@@ -0,0 +1,172 @@
+<!DOCTYPE HTML>
+<!--
+/*
+ * jQuery File Upload Plugin Test
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+-->
+<html lang="en">
+<head>
+<!-- Force latest IE rendering engine or ChromeFrame if installed -->
+<!--[if IE]>
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<![endif]-->
+<meta charset="utf-8">
+<title>jQuery File Upload Plugin Test</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="stylesheet" href="//codeorigin.jquery.com/qunit/qunit-1.14.0.css">
+</head>
+<body>
+<h1 id="qunit-header">jQuery File Upload Plugin Test</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+    <!-- The file upload form used as target for the file upload widget -->
+    <form id="fileupload" action="../server/php/" method="POST" enctype="multipart/form-data">
+        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
+       <div class="row fileupload-buttonbar">
+            <div class="col-lg-7">
+                <!-- The fileinput-button span is used to style the file input field as button -->
+                <span class="btn btn-success fileinput-button">
+                    <i class="icon-plus icon-white"></i>
+                    <span>Add files...</span>
+                    <input type="file" name="files[]" multiple>
+                </span>
+                <button type="submit" class="btn btn-primary start">
+                    <i class="icon-upload icon-white"></i>
+                    <span>Start upload</span>
+                </button>
+                <button type="reset" class="btn btn-warning cancel">
+                    <i class="icon-ban-circle icon-white"></i>
+                    <span>Cancel upload</span>
+                </button>
+                <button type="button" class="btn btn-danger delete">
+                    <i class="icon-trash icon-white"></i>
+                    <span>Delete</span>
+                </button>
+                <input type="checkbox" class="toggle">
+                <!-- The global file processing state -->
+                <span class="fileupload-process"></span>
+            </div>
+            <!-- The global progress state -->
+            <div class="col-lg-5 fileupload-progress">
+                <!-- The global progress bar -->
+                <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
+                    <div class="progress-bar progress-bar-success" style="width:0%;"></div>
+                </div>
+                <!-- The extended global progress state -->
+                <div class="progress-extended">&nbsp;</div>
+            </div>
+        </div>
+        <!-- The table listing the files available for upload/download -->
+        <table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
+    </form>
+</div>
+<!-- The template to display files available for upload -->
+<script id="template-upload" type="text/x-tmpl">
+{% for (var i=0, file; file=o.files[i]; i++) { %}
+    <tr class="template-upload">
+        <td>
+            <span class="preview"></span>
+        </td>
+        <td>
+            <p class="name">{%=file.name%}</p>
+            <strong class="error text-danger"></strong>
+        </td>
+        <td>
+            <p class="size">Processing...</p>
+            <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
+        </td>
+        <td>
+            {% if (!i && !o.options.autoUpload) { %}
+                <button class="btn btn-primary start" disabled>
+                    <i class="glyphicon glyphicon-upload"></i>
+                    <span>Start</span>
+                </button>
+            {% } %}
+            {% if (!i) { %}
+                <button class="btn btn-warning cancel">
+                    <i class="glyphicon glyphicon-ban-circle"></i>
+                    <span>Cancel</span>
+                </button>
+            {% } %}
+        </td>
+    </tr>
+{% } %}
+</script>
+<!-- The template to display files available for download -->
+<script id="template-download" type="text/x-tmpl">
+{% for (var i=0, file; file=o.files[i]; i++) { %}
+    <tr class="template-download">
+        <td>
+            <span class="preview">
+                {% if (file.thumbnailUrl) { %}
+                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
+                {% } %}
+            </span>
+        </td>
+        <td>
+            <p class="name">
+                {% if (file.url) { %}
+                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
+                {% } else { %}
+                    <span>{%=file.name%}</span>
+                {% } %}
+            </p>
+            {% if (file.error) { %}
+                <div><span class="label label-danger">Error</span> {%=file.error%}</div>
+            {% } %}
+        </td>
+        <td>
+            <span class="size">{%=o.formatFileSize(file.size)%}</span>
+        </td>
+        <td>
+            {% if (file.deleteUrl) { %}
+                <button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
+                    <i class="glyphicon glyphicon-trash"></i>
+                    <span>Delete</span>
+                </button>
+                <input type="checkbox" name="delete" value="1" class="toggle">
+            {% } else { %}
+                <button class="btn btn-warning cancel">
+                    <i class="glyphicon glyphicon-ban-circle"></i>
+                    <span>Cancel</span>
+                </button>
+            {% } %}
+        </td>
+    </tr>
+{% } %}
+</script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+<script src="../js/vendor/jquery.ui.widget.js"></script>
+<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
+<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
+<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
+<script src="../js/jquery.iframe-transport.js"></script>
+<script src="../js/jquery.fileupload.js"></script>
+<script>
+/* global window, $ */
+window.testBasicWidget = $.blueimp.fileupload;
+</script>
+<script src="../js/jquery.fileupload-process.js"></script>
+<script src="../js/jquery.fileupload-image.js"></script>
+<script src="../js/jquery.fileupload-audio.js"></script>
+<script src="../js/jquery.fileupload-video.js"></script>
+<script src="../js/jquery.fileupload-validate.js"></script>
+<script src="../js/jquery.fileupload-ui.js"></script>
+<script>
+/* global window, $ */
+window.testUIWidget = $.blueimp.fileupload;
+</script>
+<script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script>
+<script src="test.js"></script>
+</body>
+</html>

+ 1292 - 0
src/main/resources/static/static/diaowen/js/plugs/jQuery-File-Upload-9.19.2/test/test.js

@@ -0,0 +1,1292 @@
+/*
+ * jQuery File Upload Plugin Test
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * https://opensource.org/licenses/MIT
+ */
+
+/* global $, QUnit, window, document, expect, module, test, asyncTest, start, ok, strictEqual, notStrictEqual */
+
+$(function () {
+    // jshint nomen:false
+    'use strict';
+
+    QUnit.done = function () {
+        // Delete all uploaded files:
+        var url = $('#fileupload').prop('action');
+        $.getJSON(url, function (result) {
+            $.each(result.files, function (index, file) {
+                $.ajax({
+                    url: url + '?file=' + encodeURIComponent(file.name),
+                    type: 'DELETE'
+                });
+            });
+        });
+    };
+
+    var lifecycle = {
+            setup: function () {
+                // Set the .fileupload method to the basic widget method:
+                $.widget('blueimp.fileupload', window.testBasicWidget, {});
+            },
+            teardown: function () {
+                // Remove all remaining event listeners:
+                $(document).unbind();
+            }
+        },
+        lifecycleUI = {
+            setup: function () {
+                // Set the .fileupload method to the UI widget method:
+                $.widget('blueimp.fileupload', window.testUIWidget, {});
+            },
+            teardown: function () {
+                // Remove all remaining event listeners:
+                $(document).unbind();
+            }
+        };
+
+    module('Initialization', lifecycle);
+
+    test('Widget initialization', function () {
+        var fu = $('#fileupload').fileupload();
+        ok(fu.data('blueimp-fileupload') || fu.data('fileupload'));
+    });
+
+    test('Data attribute options', function () {
+        $('#fileupload').attr('data-url', 'http://example.org');
+        $('#fileupload').fileupload();
+        strictEqual(
+            $('#fileupload').fileupload('option', 'url'),
+            'http://example.org'
+        );
+    });
+
+    test('File input initialization', function () {
+        var fu = $('#fileupload').fileupload();
+        ok(
+            fu.fileupload('option', 'fileInput').length,
+            'File input field inside of the widget'
+        );
+        ok(
+            fu.fileupload('option', 'fileInput').length,
+            'Widget element as file input field'
+        );
+    });
+
+    test('Drop zone initialization', function () {
+        ok($('#fileupload').fileupload()
+            .fileupload('option', 'dropZone').length);
+    });
+
+    test('Paste zone initialization', function () {
+        ok($('#fileupload').fileupload({pasteZone: document})
+            .fileupload('option', 'pasteZone').length);
+    });
+
+    test('Event listeners initialization', function () {
+        expect(
+            $.support.xhrFormDataFileUpload ? 4 : 1
+        );
+        var eo = {
+                originalEvent: {
+                    dataTransfer: {files: [{}], types: ['Files']},
+                    clipboardData: {items: [{}]}
+                }
+            },
+            fu = $('#fileupload').fileupload({
+                pasteZone: document,
+                dragover: function () {
+                    ok(true, 'Triggers dragover callback');
+                    return false;
+                },
+                drop: function () {
+                    ok(true, 'Triggers drop callback');
+                    return false;
+                },
+                paste: function () {
+                    ok(true, 'Triggers paste callback');
+                    return false;
+                },
+                change: function () {
+                    ok(true, 'Triggers change callback');
+                    return false;
+                }
+            }),
+            fileInput = fu.fileupload('option', 'fileInput'),
+            dropZone = fu.fileupload('option', 'dropZone'),
+            pasteZone = fu.fileupload('option', 'pasteZone');
+        fileInput.trigger($.Event('change', eo));
+        dropZone.trigger($.Event('dragover', eo));
+        dropZone.trigger($.Event('drop', eo));
+        pasteZone.trigger($.Event('paste', eo));
+    });
+
+    module('API', lifecycle);
+
+    test('destroy', function () {
+        expect(4);
+        var eo = {
+                originalEvent: {
+                    dataTransfer: {files: [{}], types: ['Files']},
+                    clipboardData: {items: [{}]}
+                }
+            },
+            options = {
+                pasteZone: document,
+                dragover: function () {
+                    ok(true, 'Triggers dragover callback');
+                    return false;
+                },
+                drop: function () {
+                    ok(true, 'Triggers drop callback');
+                    return false;
+                },
+                paste: function () {
+                    ok(true, 'Triggers paste callback');
+                    return false;
+                },
+                change: function () {
+                    ok(true, 'Triggers change callback');
+                    return false;
+                }
+            },
+            fu = $('#fileupload').fileupload(options),
+            fileInput = fu.fileupload('option', 'fileInput'),
+            dropZone = fu.fileupload('option', 'dropZone'),
+            pasteZone = fu.fileupload('option', 'pasteZone');
+        dropZone.bind('dragover', options.dragover);
+        dropZone.bind('drop', options.drop);
+        pasteZone.bind('paste', options.paste);
+        fileInput.bind('change', options.change);
+        fu.fileupload('destroy');
+        fileInput.trigger($.Event('change', eo));
+        dropZone.trigger($.Event('dragover', eo));
+        dropZone.trigger($.Event('drop', eo));
+        pasteZone.trigger($.Event('paste', eo));
+    });
+
+    test('disable/enable', function () {
+        expect(
+            $.support.xhrFormDataFileUpload ? 4 : 1
+        );
+        var eo = {
+                originalEvent: {
+                    dataTransfer: {files: [{}], types: ['Files']},
+                    clipboardData: {items: [{}]}
+                }
+            },
+            fu = $('#fileupload').fileupload({
+                pasteZone: document,
+                dragover: function () {
+                    ok(true, 'Triggers dragover callback');
+                    return false;
+                },
+                drop: function () {
+                    ok(true, 'Triggers drop callback');
+                    return false;
+                },
+                paste: function () {
+                    ok(true, 'Triggers paste callback');
+                    return false;
+                },
+                change: function () {
+                    ok(true, 'Triggers change callback');
+                    return false;
+                }
+            }),
+            fileInput = fu.fileupload('option', 'fileInput'),
+            dropZone = fu.fileupload('option', 'dropZone'),
+            pasteZone = fu.fileupload('option', 'pasteZone');
+        fu.fileupload('disable');
+        fileInput.trigger($.Event('change', eo));
+        dropZone.trigger($.Event('dragover', eo));
+        dropZone.trigger($.Event('drop', eo));
+        pasteZone.trigger($.Event('paste', eo));
+        fu.fileupload('enable');
+        fileInput.trigger($.Event('change', eo));
+        dropZone.trigger($.Event('dragover', eo));
+        dropZone.trigger($.Event('drop', eo));
+        pasteZone.trigger($.Event('paste', eo));
+    });
+
+    test('option', function () {
+        expect(
+            $.support.xhrFormDataFileUpload ? 10 : 7
+        );
+        var eo = {
+                originalEvent: {
+                    dataTransfer: {files: [{}], types: ['Files']},
+                    clipboardData: {items: [{}]}
+                }
+            },
+            fu = $('#fileupload').fileupload({
+                pasteZone: document,
+                dragover: function () {
+                    ok(true, 'Triggers dragover callback');
+                    return false;
+                },
+                drop: function () {
+                    ok(true, 'Triggers drop callback');
+                    return false;
+                },
+                paste: function () {
+                    ok(true, 'Triggers paste callback');
+                    return false;
+                },
+                change: function () {
+                    ok(true, 'Triggers change callback');
+                    return false;
+                }
+            }),
+            fileInput = fu.fileupload('option', 'fileInput'),
+            dropZone = fu.fileupload('option', 'dropZone'),
+            pasteZone = fu.fileupload('option', 'pasteZone');
+        fu.fileupload('option', 'fileInput', null);
+        fu.fileupload('option', 'dropZone', null);
+        fu.fileupload('option', 'pasteZone', null);
+        fileInput.trigger($.Event('change', eo));
+        dropZone.trigger($.Event('dragover', eo));
+        dropZone.trigger($.Event('drop', eo));
+        pasteZone.trigger($.Event('paste', eo));
+        fu.fileupload('option', 'dropZone', 'body');
+        strictEqual(
+            fu.fileupload('option', 'dropZone')[0],
+            document.body,
+            'Allow a query string as parameter for the dropZone option'
+        );
+        fu.fileupload('option', 'dropZone', document);
+        strictEqual(
+            fu.fileupload('option', 'dropZone')[0],
+            document,
+            'Allow a document element as parameter for the dropZone option'
+        );
+        fu.fileupload('option', 'pasteZone', 'body');
+        strictEqual(
+            fu.fileupload('option', 'pasteZone')[0],
+            document.body,
+            'Allow a query string as parameter for the pasteZone option'
+        );
+        fu.fileupload('option', 'pasteZone', document);
+        strictEqual(
+            fu.fileupload('option', 'pasteZone')[0],
+            document,
+            'Allow a document element as parameter for the pasteZone option'
+        );
+        fu.fileupload('option', 'fileInput', ':file');
+        strictEqual(
+            fu.fileupload('option', 'fileInput')[0],
+            $(':file')[0],
+            'Allow a query string as parameter for the fileInput option'
+        );
+        fu.fileupload('option', 'fileInput', $(':file')[0]);
+        strictEqual(
+            fu.fileupload('option', 'fileInput')[0],
+            $(':file')[0],
+            'Allow a document element as parameter for the fileInput option'
+        );
+        fu.fileupload('option', 'fileInput', fileInput);
+        fu.fileupload('option', 'dropZone', dropZone);
+        fu.fileupload('option', 'pasteZone', pasteZone);
+        fileInput.trigger($.Event('change', eo));
+        dropZone.trigger($.Event('dragover', eo));
+        dropZone.trigger($.Event('drop', eo));
+        pasteZone.trigger($.Event('paste', eo));
+    });
+
+    asyncTest('add', function () {
+        expect(2);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            add: function (e, data) {
+                strictEqual(
+                    data.files[0].name,
+                    param.files[0].name,
+                    'Triggers add callback'
+                );
+            }
+        }).fileupload('add', param).fileupload(
+            'option',
+            'add',
+            function (e, data) {
+                data.submit().complete(function () {
+                    ok(true, 'data.submit() Returns a jqXHR object');
+                    start();
+                });
+            }
+        ).fileupload('add', param);
+    });
+
+    asyncTest('send', function () {
+        expect(3);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            send: function (e, data) {
+                strictEqual(
+                    data.files[0].name,
+                    'test',
+                    'Triggers send callback'
+                );
+            }
+        }).fileupload('send', param).fail(function () {
+            ok(true, 'Allows to abort the request');
+        }).complete(function () {
+            ok(true, 'Returns a jqXHR object');
+            start();
+        }).abort();
+    });
+
+    module('Callbacks', lifecycle);
+
+    asyncTest('add', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            add: function () {
+                ok(true, 'Triggers add callback');
+                start();
+            }
+        }).fileupload('add', param);
+    });
+
+    asyncTest('submit', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            submit: function () {
+                ok(true, 'Triggers submit callback');
+                start();
+                return false;
+            }
+        }).fileupload('add', param);
+    });
+
+    asyncTest('send', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            send: function () {
+                ok(true, 'Triggers send callback');
+                start();
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('done', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            done: function () {
+                ok(true, 'Triggers done callback');
+                start();
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('fail', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]},
+            fu = $('#fileupload').fileupload({
+                url: '404',
+                fail: function () {
+                    ok(true, 'Triggers fail callback');
+                    start();
+                }
+            });
+        (fu.data('blueimp-fileupload') || fu.data('fileupload'))
+            ._isXHRUpload = function () {
+                return true;
+            };
+        fu.fileupload('send', param);
+    });
+
+    asyncTest('always', function () {
+        expect(2);
+        var param = {files: [{name: 'test'}]},
+            counter = 0,
+            fu = $('#fileupload').fileupload({
+                always: function () {
+                    ok(true, 'Triggers always callback');
+                    if (counter === 1) {
+                        start();
+                    } else {
+                        counter += 1;
+                    }
+                }
+            });
+        (fu.data('blueimp-fileupload') || fu.data('fileupload'))
+            ._isXHRUpload = function () {
+                return true;
+            };
+        fu.fileupload('add', param).fileupload(
+            'option',
+            'url',
+            '404'
+        ).fileupload('add', param);
+    });
+
+    asyncTest('progress', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]},
+            counter = 0;
+        $('#fileupload').fileupload({
+            forceIframeTransport: true,
+            progress: function () {
+                ok(true, 'Triggers progress callback');
+                if (counter === 0) {
+                    start();
+                } else {
+                    counter += 1;
+                }
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('progressall', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]},
+            counter = 0;
+        $('#fileupload').fileupload({
+            forceIframeTransport: true,
+            progressall: function () {
+                ok(true, 'Triggers progressall callback');
+                if (counter === 0) {
+                    start();
+                } else {
+                    counter += 1;
+                }
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('start', function () {
+        expect(1);
+        var param = {files: [{name: '1'}, {name: '2'}]},
+            active = 0;
+        $('#fileupload').fileupload({
+            send: function () {
+                active += 1;
+            },
+            start: function () {
+                ok(!active, 'Triggers start callback before uploads');
+                start();
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('stop', function () {
+        expect(1);
+        var param = {files: [{name: '1'}, {name: '2'}]},
+            active = 0;
+        $('#fileupload').fileupload({
+            send: function () {
+                active += 1;
+            },
+            always: function () {
+                active -= 1;
+            },
+            stop: function () {
+                ok(!active, 'Triggers stop callback after uploads');
+                start();
+            }
+        }).fileupload('send', param);
+    });
+
+    test('change', function () {
+        var fu = $('#fileupload').fileupload(),
+            fuo = fu.data('blueimp-fileupload') || fu.data('fileupload'),
+            fileInput = fu.fileupload('option', 'fileInput');
+        expect(2);
+        fu.fileupload({
+            change: function (e, data) {
+                ok(true, 'Triggers change callback');
+                strictEqual(
+                    data.files.length,
+                    0,
+                    'Returns empty files list'
+                );
+            },
+            add: $.noop
+        });
+        fuo._onChange({
+            data: {fileupload: fuo},
+            target: fileInput[0]
+        });
+    });
+
+    test('paste', function () {
+        var fu = $('#fileupload').fileupload(),
+            fuo = fu.data('blueimp-fileupload') || fu.data('fileupload');
+        expect(1);
+        fu.fileupload({
+            paste: function () {
+                ok(true, 'Triggers paste callback');
+            },
+            add: $.noop
+        });
+        fuo._onPaste({
+            data: {fileupload: fuo},
+            originalEvent: {
+                dataTransfer: {files: [{}]},
+                clipboardData: {items: [{}]}
+            },
+            preventDefault: $.noop
+        });
+    });
+
+    test('drop', function () {
+        var fu = $('#fileupload').fileupload(),
+            fuo = fu.data('blueimp-fileupload') || fu.data('fileupload');
+        expect(1);
+        fu.fileupload({
+            drop: function () {
+                ok(true, 'Triggers drop callback');
+            },
+            add: $.noop
+        });
+        fuo._onDrop({
+            data: {fileupload: fuo},
+            originalEvent: {
+                dataTransfer: {files: [{}]},
+                clipboardData: {items: [{}]}
+            },
+            preventDefault: $.noop
+        });
+    });
+
+    test('dragover', function () {
+        var fu = $('#fileupload').fileupload(),
+            fuo = fu.data('blueimp-fileupload') || fu.data('fileupload');
+        expect(1);
+        fu.fileupload({
+            dragover: function () {
+                ok(true, 'Triggers dragover callback');
+            },
+            add: $.noop
+        });
+        fuo._onDragOver({
+            data: {fileupload: fuo},
+            originalEvent: {dataTransfer: {types: ['Files']}},
+            preventDefault: $.noop
+        });
+    });
+
+    module('Options', lifecycle);
+
+    test('paramName', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            paramName: null,
+            send: function (e, data) {
+                strictEqual(
+                    data.paramName[0],
+                    data.fileInput.prop('name'),
+                    'Takes paramName from file input field if not set'
+                );
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    test('url', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            url: null,
+            send: function (e, data) {
+                strictEqual(
+                    data.url,
+                    $(data.fileInput.prop('form')).prop('action'),
+                    'Takes url from form action if not set'
+                );
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    test('type', function () {
+        expect(2);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            type: null,
+            send: function (e, data) {
+                strictEqual(
+                    data.type,
+                    'POST',
+                    'Request type is "POST" if not set to "PUT"'
+                );
+                return false;
+            }
+        }).fileupload('send', param);
+        $('#fileupload').fileupload({
+            type: 'PUT',
+            send: function (e, data) {
+                strictEqual(
+                    data.type,
+                    'PUT',
+                    'Request type is "PUT" if set to "PUT"'
+                );
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    test('replaceFileInput', function () {
+        var fu = $('#fileupload').fileupload(),
+            fuo = fu.data('blueimp-fileupload') || fu.data('fileupload'),
+            fileInput = fu.fileupload('option', 'fileInput'),
+            fileInputElement = fileInput[0];
+        expect(2);
+        fu.fileupload({
+            replaceFileInput: false,
+            change: function () {
+                strictEqual(
+                    fu.fileupload('option', 'fileInput')[0],
+                    fileInputElement,
+                    'Keeps file input with replaceFileInput: false'
+                );
+            },
+            add: $.noop
+        });
+        fuo._onChange({
+            data: {fileupload: fuo},
+            target: fileInput[0]
+        });
+        fu.fileupload({
+            replaceFileInput: true,
+            change: function () {
+                notStrictEqual(
+                    fu.fileupload('option', 'fileInput')[0],
+                    fileInputElement,
+                    'Replaces file input with replaceFileInput: true'
+                );
+            },
+            add: $.noop
+        });
+        fuo._onChange({
+            data: {fileupload: fuo},
+            target: fileInput[0]
+        });
+    });
+
+    asyncTest('forceIframeTransport', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            forceIframeTransport: true,
+            done: function (e, data) {
+                strictEqual(
+                    data.dataType.substr(0, 6),
+                    'iframe',
+                    'Iframe Transport is used'
+                );
+                start();
+            }
+        }).fileupload('send', param);
+    });
+
+    test('singleFileUploads', function () {
+        expect(3);
+        var fu = $('#fileupload').fileupload(),
+            param = {files: [{name: '1'}, {name: '2'}]},
+            index = 1;
+        (fu.data('blueimp-fileupload') || fu.data('fileupload'))
+            ._isXHRUpload = function () {
+                return true;
+            };
+        $('#fileupload').fileupload({
+            singleFileUploads: true,
+            add: function () {
+                ok(true, 'Triggers callback number ' + index.toString());
+                index += 1;
+            }
+        }).fileupload('add', param).fileupload(
+            'option',
+            'singleFileUploads',
+            false
+        ).fileupload('add', param);
+    });
+
+    test('limitMultiFileUploads', function () {
+        expect(3);
+        var fu = $('#fileupload').fileupload(),
+            param = {files: [
+                {name: '1'},
+                {name: '2'},
+                {name: '3'},
+                {name: '4'},
+                {name: '5'}
+            ]},
+            index = 1;
+        (fu.data('blueimp-fileupload') || fu.data('fileupload'))
+            ._isXHRUpload = function () {
+                return true;
+            };
+        $('#fileupload').fileupload({
+            singleFileUploads: false,
+            limitMultiFileUploads: 2,
+            add: function () {
+                ok(true, 'Triggers callback number ' + index.toString());
+                index += 1;
+            }
+        }).fileupload('add', param);
+    });
+
+    test('limitMultiFileUploadSize', function () {
+        expect(7);
+        var fu = $('#fileupload').fileupload(),
+            param = {files: [
+                {name: '1-1', size: 100000},
+                {name: '1-2', size: 40000},
+                {name: '2-1', size: 100000},
+                {name: '3-1', size: 50000},
+                {name: '3-2', size: 40000},
+                {name: '4-1', size: 45000} // New request due to limitMultiFileUploads
+            ]},
+            param2 = {files: [
+                {name: '5-1'},
+                {name: '5-2'},
+                {name: '6-1'},
+                {name: '6-2'},
+                {name: '7-1'}
+            ]},
+            index = 1;
+        (fu.data('blueimp-fileupload') || fu.data('fileupload'))
+            ._isXHRUpload = function () {
+                return true;
+            };
+        $('#fileupload').fileupload({
+            singleFileUploads: false,
+            limitMultiFileUploads: 2,
+            limitMultiFileUploadSize: 150000,
+            limitMultiFileUploadSizeOverhead: 5000,
+            add: function () {
+                ok(true, 'Triggers callback number ' + index.toString());
+                index += 1;
+            }
+        }).fileupload('add', param).fileupload('add', param2);
+    });
+
+    asyncTest('sequentialUploads', function () {
+        expect(6);
+        var param = {files: [
+                {name: '1'},
+                {name: '2'},
+                {name: '3'},
+                {name: '4'},
+                {name: '5'},
+                {name: '6'}
+            ]},
+            addIndex = 0,
+            sendIndex = 0,
+            loadIndex = 0,
+            fu = $('#fileupload').fileupload({
+                sequentialUploads: true,
+                add: function (e, data) {
+                    addIndex += 1;
+                    if (addIndex === 4) {
+                        data.submit().abort();
+                    } else {
+                        data.submit();
+                    }
+                },
+                send: function () {
+                    sendIndex += 1;
+                },
+                done: function () {
+                    loadIndex += 1;
+                    strictEqual(sendIndex, loadIndex, 'upload in order');
+                },
+                fail: function (e, data) {
+                    strictEqual(data.errorThrown, 'abort', 'upload aborted');
+                },
+                stop: function () {
+                    start();
+                }
+            });
+        (fu.data('blueimp-fileupload') || fu.data('fileupload'))
+            ._isXHRUpload = function () {
+                return true;
+            };
+        fu.fileupload('add', param);
+    });
+
+    asyncTest('limitConcurrentUploads', function () {
+        expect(12);
+        var param = {files: [
+                {name: '1'},
+                {name: '2'},
+                {name: '3'},
+                {name: '4'},
+                {name: '5'},
+                {name: '6'},
+                {name: '7'},
+                {name: '8'},
+                {name: '9'},
+                {name: '10'},
+                {name: '11'},
+                {name: '12'}
+            ]},
+            addIndex = 0,
+            sendIndex = 0,
+            loadIndex = 0,
+            fu = $('#fileupload').fileupload({
+                limitConcurrentUploads: 3,
+                add: function (e, data) {
+                    addIndex += 1;
+                    if (addIndex === 4) {
+                        data.submit().abort();
+                    } else {
+                        data.submit();
+                    }
+                },
+                send: function () {
+                    sendIndex += 1;
+                },
+                done: function () {
+                    loadIndex += 1;
+                    ok(sendIndex - loadIndex < 3);
+                },
+                fail: function (e, data) {
+                    strictEqual(data.errorThrown, 'abort', 'upload aborted');
+                },
+                stop: function () {
+                    start();
+                }
+            });
+        (fu.data('blueimp-fileupload') || fu.data('fileupload'))
+            ._isXHRUpload = function () {
+                return true;
+            };
+        fu.fileupload('add', param);
+    });
+
+    if ($.support.xhrFileUpload) {
+        asyncTest('multipart', function () {
+            expect(2);
+            var param = {files: [{
+                    name: 'test.png',
+                    size: 123,
+                    type: 'image/png'
+                }]},
+                fu = $('#fileupload').fileupload({
+                    multipart: false,
+                    always: function (e, data) {
+                        strictEqual(
+                            data.contentType,
+                            param.files[0].type,
+                            'non-multipart upload sets file type as contentType'
+                        );
+                        strictEqual(
+                            data.headers['Content-Disposition'],
+                            'attachment; filename="' + param.files[0].name + '"',
+                            'non-multipart upload sets Content-Disposition header'
+                        );
+                        start();
+                    }
+                });
+            fu.fileupload('send', param);
+        });
+    }
+
+    module('UI Initialization', lifecycleUI);
+
+    test('Widget initialization', function () {
+        var fu = $('#fileupload').fileupload();
+        ok(fu.data('blueimp-fileupload') || fu.data('fileupload'));
+        ok(
+            $('#fileupload').fileupload('option', 'uploadTemplate').length,
+            'Initialized upload template'
+        );
+        ok(
+            $('#fileupload').fileupload('option', 'downloadTemplate').length,
+            'Initialized download template'
+        );
+    });
+
+    test('Buttonbar event listeners', function () {
+        var buttonbar = $('#fileupload .fileupload-buttonbar'),
+            files = [{name: 'test'}];
+        expect(4);
+        $('#fileupload').fileupload({
+            send: function () {
+                ok(true, 'Started file upload via global start button');
+            },
+            fail: function (e, data) {
+                ok(true, 'Canceled file upload via global cancel button');
+                data.context.remove();
+            },
+            destroy: function () {
+                ok(true, 'Delete action called via global delete button');
+            }
+        });
+        $('#fileupload').fileupload('add', {files: files});
+        buttonbar.find('.cancel').click();
+        $('#fileupload').fileupload('add', {files: files});
+        buttonbar.find('.start').click();
+        buttonbar.find('.cancel').click();
+        files[0].deleteUrl = 'http://example.org/banana.jpg';
+        ($('#fileupload').data('blueimp-fileupload') ||
+                $('#fileupload').data('fileupload'))
+            ._renderDownload(files)
+            .appendTo($('#fileupload .files')).show()
+            .find('.toggle').click();
+        buttonbar.find('.delete').click();
+    });
+
+    module('UI API', lifecycleUI);
+
+    test('destroy', function () {
+        var buttonbar = $('#fileupload .fileupload-buttonbar'),
+            files = [{name: 'test'}];
+        expect(1);
+        $('#fileupload').fileupload({
+            send: function () {
+                ok(true, 'This test should not run');
+                return false;
+            }
+        })
+            .fileupload('add', {files: files})
+            .fileupload('destroy');
+        buttonbar.find('.start').click(function () {
+            ok(true, 'Clicked global start button');
+            return false;
+        }).click();
+    });
+
+    test('disable/enable', function () {
+        var buttonbar = $('#fileupload .fileupload-buttonbar');
+        $('#fileupload').fileupload();
+        $('#fileupload').fileupload('disable');
+        strictEqual(
+            buttonbar.find('input[type=file], button').not(':disabled').length,
+            0,
+            'Disables the buttonbar buttons'
+        );
+        $('#fileupload').fileupload('enable');
+        strictEqual(
+            buttonbar.find('input[type=file], button').not(':disabled').length,
+            4,
+            'Enables the buttonbar buttons'
+        );
+    });
+
+    module('UI Callbacks', lifecycleUI);
+
+    test('destroy', function () {
+        expect(3);
+        $('#fileupload').fileupload({
+            destroy: function (e, data) {
+                ok(true, 'Triggers destroy callback');
+                strictEqual(
+                    data.url,
+                    'test',
+                    'Passes over deletion url parameter'
+                );
+                strictEqual(
+                    data.type,
+                    'DELETE',
+                    'Passes over deletion request type parameter'
+                );
+            }
+        });
+        ($('#fileupload').data('blueimp-fileupload') ||
+                $('#fileupload').data('fileupload'))
+            ._renderDownload([{
+                name: 'test',
+                deleteUrl: 'test',
+                deleteType: 'DELETE'
+            }])
+            .appendTo($('#fileupload .files'))
+            .show()
+            .find('.toggle').click();
+        $('#fileupload .fileupload-buttonbar .delete').click();
+    });
+
+    asyncTest('added', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            added: function (e, data) {
+                start();
+                strictEqual(
+                    data.files[0].name,
+                    param.files[0].name,
+                    'Triggers added callback'
+                );
+            },
+            send: function () {
+                return false;
+            }
+        }).fileupload('add', param);
+    });
+
+    asyncTest('started', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            started: function () {
+                start();
+                ok('Triggers started callback');
+                return false;
+            },
+            sent: function () {
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('sent', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            sent: function (e, data) {
+                start();
+                strictEqual(
+                    data.files[0].name,
+                    param.files[0].name,
+                    'Triggers sent callback'
+                );
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('completed', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            completed: function () {
+                start();
+                ok('Triggers completed callback');
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('failed', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            failed: function () {
+                start();
+                ok('Triggers failed callback');
+                return false;
+            }
+        }).fileupload('send', param).abort();
+    });
+
+    asyncTest('stopped', function () {
+        expect(1);
+        var param = {files: [{name: 'test'}]};
+        $('#fileupload').fileupload({
+            stopped: function () {
+                start();
+                ok('Triggers stopped callback');
+                return false;
+            }
+        }).fileupload('send', param);
+    });
+
+    asyncTest('destroyed', function () {
+        expect(1);
+        $('#fileupload').fileupload({
+            dataType: 'html',
+            destroyed: function () {
+                start();
+                ok(true, 'Triggers destroyed callback');
+            }
+        });
+        ($('#fileupload').data('blueimp-fileupload') ||
+                $('#fileupload').data('fileupload'))
+            ._renderDownload([{
+                name: 'test',
+                deleteUrl: '.',
+                deleteType: 'GET'
+            }])
+            .appendTo($('#fileupload .files'))
+            .show()
+            .find('.toggle').click();
+        $('#fileupload .fileupload-buttonbar .delete').click();
+    });
+
+    module('UI Options', lifecycleUI);
+
+    test('autoUpload', function () {
+        expect(1);
+        $('#fileupload')
+            .fileupload({
+                autoUpload: true,
+                send: function () {
+                    ok(true, 'Started file upload automatically');
+                    return false;
+                }
+            })
+            .fileupload('add', {files: [{name: 'test'}]})
+            .fileupload('option', 'autoUpload', false)
+            .fileupload('add', {files: [{name: 'test'}]});
+    });
+
+    test('maxNumberOfFiles', function () {
+        expect(3);
+        var addIndex = 0,
+            sendIndex = 0;
+        $('#fileupload')
+            .fileupload({
+                autoUpload: true,
+                maxNumberOfFiles: 3,
+                singleFileUploads: false,
+                send: function () {
+                    strictEqual(
+                        sendIndex += 1,
+                        addIndex
+                    );
+                },
+                progress: $.noop,
+                progressall: $.noop,
+                done: $.noop,
+                stop: $.noop
+            })
+            .fileupload('add', {files: [{name: (addIndex += 1)}]})
+            .fileupload('add', {files: [{name: (addIndex += 1)}]})
+            .fileupload('add', {files: [{name: (addIndex += 1)}]})
+            .fileupload('add', {files: [{name: 'test'}]});
+    });
+
+    test('maxFileSize', function () {
+        expect(2);
+        var addIndex = 0,
+            sendIndex = 0;
+        $('#fileupload')
+            .fileupload({
+                autoUpload: true,
+                maxFileSize: 1000,
+                send: function () {
+                    strictEqual(
+                        sendIndex += 1,
+                        addIndex
+                    );
+                    return false;
+                }
+            })
+            .fileupload('add', {files: [{
+                name: (addIndex += 1)
+            }]})
+            .fileupload('add', {files: [{
+                name: (addIndex += 1),
+                size: 999
+            }]})
+            .fileupload('add', {files: [{
+                name: 'test',
+                size: 1001
+            }]})
+            .fileupload({
+                send: function (e, data) {
+                    ok(
+                        !$.blueimp.fileupload.prototype.options
+                            .send.call(this, e, data)
+                    );
+                    return false;
+                }
+            });
+    });
+
+    test('minFileSize', function () {
+        expect(2);
+        var addIndex = 0,
+            sendIndex = 0;
+        $('#fileupload')
+            .fileupload({
+                autoUpload: true,
+                minFileSize: 1000,
+                send: function () {
+                    strictEqual(
+                        sendIndex += 1,
+                        addIndex
+                    );
+                    return false;
+                }
+            })
+            .fileupload('add', {files: [{
+                name: (addIndex += 1)
+            }]})
+            .fileupload('add', {files: [{
+                name: (addIndex += 1),
+                size: 1001
+            }]})
+            .fileupload('add', {files: [{
+                name: 'test',
+                size: 999
+            }]})
+            .fileupload({
+                send: function (e, data) {
+                    ok(
+                        !$.blueimp.fileupload.prototype.options
+                            .send.call(this, e, data)
+                    );
+                    return false;
+                }
+            });
+    });
+
+    test('acceptFileTypes', function () {
+        expect(2);
+        var addIndex = 0,
+            sendIndex = 0;
+        $('#fileupload')
+            .fileupload({
+                autoUpload: true,
+                acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
+                disableImageMetaDataLoad: true,
+                send: function () {
+                    strictEqual(
+                        sendIndex += 1,
+                        addIndex
+                    );
+                    return false;
+                }
+            })
+            .fileupload('add', {files: [{
+                name: (addIndex += 1) + '.jpg'
+            }]})
+            .fileupload('add', {files: [{
+                name: (addIndex += 1),
+                type: 'image/jpeg'
+            }]})
+            .fileupload('add', {files: [{
+                name: 'test.txt',
+                type: 'text/plain'
+            }]})
+            .fileupload({
+                send: function (e, data) {
+                    ok(
+                        !$.blueimp.fileupload.prototype.options
+                            .send.call(this, e, data)
+                    );
+                    return false;
+                }
+            });
+    });
+
+    test('acceptFileTypes as HTML5 data attribute', function () {
+        expect(2);
+        var regExp = /(\.|\/)(gif|jpe?g|png)$/i;
+        $('#fileupload')
+            .attr('data-accept-file-types', regExp.toString())
+            .fileupload();
+        strictEqual(
+            $.type($('#fileupload').fileupload('option', 'acceptFileTypes')),
+            $.type(regExp)
+        );
+        strictEqual(
+            $('#fileupload').fileupload('option', 'acceptFileTypes').toString(),
+            regExp.toString()
+        );
+    });
+
+});

文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/js/app.86a8f295728ae093d34a.js


文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/js/app.86a8f295728ae093d34a.js.map


文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/js/app.ba05fbe971394f479030.js


文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/js/app.ba05fbe971394f479030.js.map


文件差异内容过多而无法显示
+ 0 - 0
src/main/resources/static/static/js/manifest.2ae2e69a05c33dfc65f8.js.map


部分文件因为文件数量过多而无法显示