作者 申海龙

支持EXCEL导入预配的功能

1 package com.agent.controller.agent; 1 package com.agent.controller.agent;
2 2
  3 +import java.io.*;
3 import java.sql.Connection; 4 import java.sql.Connection;
4 import java.sql.ResultSet; 5 import java.sql.ResultSet;
5 import java.sql.SQLException; 6 import java.sql.SQLException;
6 import java.sql.Statement; 7 import java.sql.Statement;
7 -import java.util.ArrayList;  
8 -import java.util.Date;  
9 -import java.util.HashMap;  
10 -import java.util.List;  
11 -import java.util.Map;  
12 -import java.util.Set; 8 +import java.text.SimpleDateFormat;
  9 +import java.util.*;
13 10
14 import javax.annotation.Resource; 11 import javax.annotation.Resource;
15 import javax.servlet.http.HttpServletRequest; 12 import javax.servlet.http.HttpServletRequest;
16 import javax.servlet.http.HttpServletResponse; 13 import javax.servlet.http.HttpServletResponse;
  14 +import javax.servlet.http.HttpSession;
  15 +import javax.servlet.http.Part;
17 16
  17 +import com.agent.entity.agent.*;
18 import com.agent.service.system.UserService; 18 import com.agent.service.system.UserService;
  19 +import com.agent.util.ExcelUtil;
19 import com.agent.vo.agent.ManifestVo; 20 import com.agent.vo.agent.ManifestVo;
  21 +import com.framework.util.DateFormat;
20 import org.apache.commons.collections.CollectionUtils; 22 import org.apache.commons.collections.CollectionUtils;
21 import org.apache.commons.lang.StringUtils; 23 import org.apache.commons.lang.StringUtils;
22 import org.apache.shiro.SecurityUtils; 24 import org.apache.shiro.SecurityUtils;
23 import org.slf4j.Logger; 25 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory; 26 import org.slf4j.LoggerFactory;
25 -import org.springframework.beans.factory.annotation.Autowired;  
26 import org.springframework.stereotype.Controller; 27 import org.springframework.stereotype.Controller;
27 import org.springframework.ui.Model; 28 import org.springframework.ui.Model;
28 -import org.springframework.web.bind.annotation.RequestMapping;  
29 -import org.springframework.web.bind.annotation.RequestMethod;  
30 -import org.springframework.web.bind.annotation.ResponseBody; 29 +import org.springframework.web.bind.annotation.*;
31 30
32 import com.agent.controller.BasicController; 31 import com.agent.controller.BasicController;
33 import com.agent.entity.Constant; 32 import com.agent.entity.Constant;
34 -import com.agent.entity.agent.BasicAgentEntity;  
35 -import com.agent.entity.agent.ManifestBillEntity;  
36 -import com.agent.entity.agent.ManifestEntity;  
37 -import com.agent.entity.agent.PackageTypeEntity;  
38 -import com.agent.entity.agent.PreparesecondaryEntity;  
39 -import com.agent.entity.agent.PubDgEntity;  
40 -import com.agent.entity.agent.TBasCarrierEntity;  
41 -import com.agent.entity.agent.WaybillReceiptEntity;  
42 -import com.agent.entity.agent.WaybillReceiptType;  
43 import com.agent.entity.system.UserEntity; 33 import com.agent.entity.system.UserEntity;
44 import com.agent.service.agent.BasicAgentService; 34 import com.agent.service.agent.BasicAgentService;
45 import com.agent.service.agent.ConsigneeService; 35 import com.agent.service.agent.ConsigneeService;
@@ -88,6 +78,7 @@ import com.framework.util.MessageType; @@ -88,6 +78,7 @@ import com.framework.util.MessageType;
88 import com.plugin.easyui.DataGrid; 78 import com.plugin.easyui.DataGrid;
89 import com.plugin.easyui.EasyPage; 79 import com.plugin.easyui.EasyPage;
90 80
  81 +import org.springframework.web.multipart.MultipartFile;
91 import tools.DBConnection; 82 import tools.DBConnection;
92 import tools.NumKit; 83 import tools.NumKit;
93 import tools.Tools; 84 import tools.Tools;
@@ -2139,4 +2130,156 @@ public class ManifestController extends BasicController { @@ -2139,4 +2130,156 @@ public class ManifestController extends BasicController {
2139 return model; 2130 return model;
2140 } 2131 }
2141 2132
  2133 +
  2134 + @RequestMapping(value = "/excelView")
  2135 + public String excelView(){
  2136 + return "manifest/excel_upload";
  2137 + }
  2138 +
  2139 + @RequestMapping(value = "/excelUpload")
  2140 + @ResponseBody
  2141 + public ResponseModel excelUpload(HttpServletRequest request,
  2142 + HttpServletResponse response,
  2143 + HttpSession session,
  2144 + @RequestParam MultipartFile file) throws IOException {
  2145 + ResponseModel model = new ResponseModel();
  2146 + //获取当前登录用户id
  2147 + UserEntity user = (UserEntity) session.getAttribute("user");
  2148 + Long userId = user.getId();
  2149 +
  2150 + List<ArrayList<String>> readResult = null;//总行记录
  2151 + try {
  2152 +
  2153 + //判断文件是否为空
  2154 + if (file.isEmpty()) {
  2155 + model.setStatus(500);
  2156 + model.setMsg("上传文件为空");
  2157 + }
  2158 + //判断文件大小
  2159 + long size = file.getSize();
  2160 + String name = file.getOriginalFilename();
  2161 + if (StringUtils.isBlank(name) || size == 0) {
  2162 + model.setStatus(500);
  2163 + model.setMsg("上传文件为空");
  2164 + }
  2165 + String postfix = ExcelUtil.getPostfix(name);
  2166 + //读取文件内容
  2167 + if (StringUtils.equals("xlsx", postfix)) {
  2168 + readResult = ExcelUtil.readXlsx(file);
  2169 + } else if (StringUtils.equals("xls", postfix)) {
  2170 + readResult = ExcelUtil.readXls(file);
  2171 + } else {
  2172 + model.setStatus(500);
  2173 + model.setMsg("文件类型错误");
  2174 + }
  2175 +
  2176 + if (readResult == null || readResult.size() == 0) {
  2177 + model.setStatus(500);
  2178 + model.setMsg("文件解析失败");
  2179 + }
  2180 +
  2181 +
  2182 + for (ArrayList<String> arr: readResult) {
  2183 +
  2184 + if (!StringUtils.isBlank(arr.get(1))){
  2185 + String s1 = arr.get(1);
  2186 + String substring = s1.substring(0, 3);
  2187 + String substring1 = s1.substring(3);
  2188 + String wbm = substring+"-"+substring1;
  2189 + //查询主单号时候存在
  2190 + ManifestEntity wbm1 = manifestService.findWbm(wbm);
  2191 + if (wbm1==null){
  2192 + ManifestEntity manifestEntity = new ManifestEntity();
  2193 + manifestEntity.setUSER_ID(userId);
  2194 + //主单号
  2195 + manifestEntity.setWaybillnomaster(wbm);
  2196 + //分单号
  2197 +
  2198 + //航班号
  2199 + manifestEntity.setFlightno(arr.get(3));
  2200 + //航班日期
  2201 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
  2202 + String s = arr.get(4);
  2203 + Date parse = simpleDateFormat.parse(s);
  2204 + manifestEntity.setFlightdate(parse);
  2205 + //承运人代码
  2206 + manifestEntity.setCarrier(arr.get(5));
  2207 + //运费支付方式
  2208 + manifestEntity.setPaymode(arr.get(6));
  2209 + //装货地代码
  2210 + manifestEntity.setOriginatingstation(arr.get(7));
  2211 + //卸货地代码
  2212 + manifestEntity.setDestinationstation(arr.get(8));
  2213 + //货物装载运输时间
  2214 + SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyyMMddHHmmss");
  2215 + manifestEntity.setStowagedate(simpleDateFormat1.parse(arr.get(9)));
  2216 + //海关关区代码
  2217 + manifestEntity.setCustomscode(arr.get(10));
  2218 +
  2219 + //中转启运地代码
  2220 +
  2221 + //中转目的地代码
  2222 +
  2223 + //货物件数
  2224 + manifestEntity.setTotalpiece(arr.get(13));
  2225 + //货物毛重
  2226 + manifestEntity.setTotalweight(arr.get(14));
  2227 + //货物简要描述
  2228 + manifestEntity.setProductname(arr.get(15));
  2229 + //发货人代码
  2230 + manifestEntity.setShpcusid(arr.get(16));
  2231 + //发货人名称
  2232 + manifestEntity.setCo_name(arr.get(17));
  2233 + //发货人地址
  2234 + manifestEntity.setCo_address(arr.get(18));
  2235 + //发货人国家代码
  2236 + manifestEntity.setSh_country(arr.get(19));
  2237 + //发货人传真
  2238 + manifestEntity.setSh_fax(arr.get(20));
  2239 + //发货人联系号码
  2240 + manifestEntity.setCo_telephone(arr.get(21));
  2241 + //收货人代码
  2242 + manifestEntity.setCnecusid(arr.get(22));
  2243 + //收货人名称
  2244 + manifestEntity.setSh_name(arr.get(23));
  2245 + //收货人地址
  2246 + manifestEntity.setSh_address(arr.get(24));
  2247 + //收货人城市
  2248 + manifestEntity.setSh_city(arr.get(25));
  2249 + //收货人国家代码
  2250 + manifestEntity.setSh_country(arr.get(26));
  2251 + //收货人传真
  2252 + manifestEntity.setSh_fax(arr.get(27));
  2253 + //收货人联系号码
  2254 + manifestEntity.setSh_telephone(arr.get(28));
  2255 + //危险品编号
  2256 +
  2257 + //危险品联系人姓名
  2258 +
  2259 + //危险品通讯方式类别代码
  2260 +
  2261 + //危险品联系人联系号码
  2262 +
  2263 + //货物海关状态代码
  2264 + manifestEntity.setCustomsstatus(arr.get(33));
  2265 + manifestService.save(manifestEntity);
  2266 + model.setStatus(200);
  2267 + }else {
  2268 + model.setStatus(201);
  2269 + model.setMsg(wbm1.getWaybillnomaster()+"单号已存在");
  2270 + break;
  2271 + }
  2272 + }else {
  2273 + break;
  2274 + }
  2275 + }
  2276 +
  2277 + } catch (Exception e) {
  2278 + model.setStatus(500);
  2279 + model.setMsg("网络异常");
  2280 + e.printStackTrace();
  2281 + }
  2282 + return model;
  2283 + }
  2284 +
2142 } 2285 }
@@ -290,27 +290,6 @@ public class ManifestEntity extends BasicEntity implements Serializable { @@ -290,27 +290,6 @@ public class ManifestEntity extends BasicEntity implements Serializable {
290 private Long USER_ID; // 报文所属的用户id 290 private Long USER_ID; // 报文所属的用户id
291 291
292 292
293 - /*//BasicAgentEntity 货代 代理人三字码  
294 - private String agentCode;  
295 -  
296 - //UserEntity 用户账号  
297 - private String loginaccount;  
298 -  
299 - public String getAgentCode() {  
300 - return agentCode;  
301 - }  
302 -  
303 - public void setAgentCode(String agentCode) {  
304 - this.agentCode = agentCode;  
305 - }  
306 -  
307 - public String getLoginaccount() {  
308 - return loginaccount;  
309 - }  
310 -  
311 - public void setLoginaccount(String loginaccount) {  
312 - this.loginaccount = loginaccount;  
313 - }*/  
314 293
315 public String getUnlodingcode() { 294 public String getUnlodingcode() {
316 return StringUtils.isBlank(unlodingcode) ? getDestinationstation() : unlodingcode; 295 return StringUtils.isBlank(unlodingcode) ? getDestinationstation() : unlodingcode;
@@ -46,5 +46,8 @@ public interface ManifestRepository extends PagingAndSortingRepository<ManifestE @@ -46,5 +46,8 @@ public interface ManifestRepository extends PagingAndSortingRepository<ManifestE
46 @Query(value = "SELECT * FROM MANIFEST WHERE USER_ID=?1", nativeQuery = true) 46 @Query(value = "SELECT * FROM MANIFEST WHERE USER_ID=?1", nativeQuery = true)
47 public List<ManifestEntity> queryByUserId(Long user_id); 47 public List<ManifestEntity> queryByUserId(Long user_id);
48 48
  49 + @Query(value = "SELECT * FROM MANIFEST WHERE WAYBILLNOMASTER=?1", nativeQuery = true)
  50 + public ManifestEntity findWbm(String wbm);
  51 +
49 52
50 } 53 }
@@ -1049,4 +1049,9 @@ public class ManifestService extends BasicService<ManifestEntity> { @@ -1049,4 +1049,9 @@ public class ManifestService extends BasicService<ManifestEntity> {
1049 1049
1050 } 1050 }
1051 1051
  1052 + //查询主单号是否存在
  1053 + public ManifestEntity findWbm(String wbm){
  1054 + return manifestRepository.findWbm(wbm);
  1055 + }
  1056 +
1052 } 1057 }
  1 +package com.agent.util;
  2 +
  3 +import com.framework.util.StringUtils;
  4 +import org.apache.poi.hssf.usermodel.HSSFCell;
  5 +import org.apache.poi.hssf.usermodel.HSSFRow;
  6 +import org.apache.poi.hssf.usermodel.HSSFSheet;
  7 +import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  8 +import org.apache.poi.ss.usermodel.Cell;
  9 +import org.apache.poi.xssf.usermodel.XSSFCell;
  10 +import org.apache.poi.xssf.usermodel.XSSFRow;
  11 +import org.apache.poi.xssf.usermodel.XSSFSheet;
  12 +import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  13 +import org.springframework.web.multipart.MultipartFile;
  14 +
  15 +import java.io.InputStream;
  16 +import java.util.ArrayList;
  17 +import java.util.List;
  18 +
  19 +/**
  20 + * @Auther: shenhl
  21 + * @Date: 2019/3/27 09:41
  22 + */
  23 +public class ExcelUtil {
  24 +
  25 +
  26 +
  27 + /**
  28 + * 读取.xlsx 内容
  29 + * @param file
  30 + * @return
  31 + * @throws
  32 + */
  33 + public static List<ArrayList<String>> readXlsx (MultipartFile file) {
  34 + List<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
  35 + InputStream input = null;
  36 + XSSFWorkbook wb = null;
  37 + try {
  38 + input = file.getInputStream();
  39 + //创建文档
  40 + wb = new XSSFWorkbook(input);
  41 + ArrayList<String> rowList = null;
  42 + int totoalRows = 0;//总行数
  43 + int totalCells = 0;//总列数
  44 + //读取sheet(页)
  45 + for (int sheetIndex = 0 ; sheetIndex < wb.getNumberOfSheets(); sheetIndex++) {
  46 + XSSFSheet xssfSheet = wb.getSheetAt(sheetIndex);
  47 +
  48 + if (xssfSheet == null) {
  49 + continue;
  50 + }
  51 + totoalRows = xssfSheet.getLastRowNum();
  52 + //读取row
  53 + for (int rowIndex = 2; rowIndex <= totoalRows; rowIndex++) {
  54 + XSSFRow xssfRow = xssfSheet.getRow(rowIndex);
  55 +
  56 + if (xssfRow == null) {
  57 + continue;
  58 + }
  59 + rowList = new ArrayList<String>();
  60 + totalCells = xssfRow.getLastCellNum();
  61 +
  62 + //读取列
  63 + for (int cellIndex = 0; cellIndex < totalCells; cellIndex++) {
  64 + XSSFCell xssfCell = xssfRow.getCell(cellIndex);
  65 + if (xssfCell == null) {
  66 + rowList.add("");
  67 + } else {
  68 + xssfCell.setCellType(Cell.CELL_TYPE_STRING);
  69 + rowList.add(String.valueOf(xssfCell.getStringCellValue()));
  70 + }
  71 + }
  72 +
  73 + list.add(rowList);
  74 +
  75 + }
  76 + }
  77 + } catch (Exception e) {
  78 + e.printStackTrace();
  79 + return null;
  80 + } finally {
  81 + try {
  82 + if ( wb != null) {
  83 + wb.close();
  84 + }
  85 + if (input != null) {
  86 + input.close();
  87 + }
  88 + } catch (Exception e) {
  89 + }
  90 + }
  91 +
  92 + return list;
  93 + }
  94 +
  95 +
  96 +
  97 + /**
  98 + * 读取 .xls内容
  99 + * @param file
  100 + * @return
  101 + * @throws
  102 + */
  103 + public static List<ArrayList<String>> readXls (MultipartFile file) {
  104 + List<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
  105 +
  106 + //创建输入流
  107 + InputStream input = null;
  108 + //创建文档
  109 + HSSFWorkbook wb = null;
  110 +
  111 + try {
  112 + input = file.getInputStream();
  113 + //创建文档
  114 + wb = new HSSFWorkbook(input);
  115 +
  116 + ArrayList<String> rowList = null;
  117 + int totoalRows = 0;//总行数
  118 + int totalCells = 0;//总列数
  119 + //读取sheet(页)
  120 + for (int sheetIndex = 0 ; sheetIndex < wb.getNumberOfSheets(); sheetIndex++) {
  121 + HSSFSheet hssfSheet = wb.getSheetAt(sheetIndex);
  122 +
  123 + if (hssfSheet == null) {
  124 + continue;
  125 + }
  126 +
  127 + totoalRows = hssfSheet.getLastRowNum();
  128 + //读取row
  129 + for (int rowIndex = 2; rowIndex <= totoalRows; rowIndex++) {
  130 + HSSFRow hssfRow = hssfSheet.getRow(rowIndex);
  131 +
  132 + if (hssfRow == null) {
  133 + continue;
  134 + }
  135 + rowList = new ArrayList<String>();
  136 + totalCells = hssfRow.getLastCellNum();
  137 +
  138 + //读取列
  139 + for (int cellIndex = 0; cellIndex < totalCells; cellIndex++) {
  140 + HSSFCell hssfCell = hssfRow.getCell(cellIndex);
  141 + if (hssfCell == null) {
  142 + rowList.add("");
  143 + } else {
  144 + hssfCell.setCellType(Cell.CELL_TYPE_STRING);
  145 + rowList.add(String.valueOf(hssfCell.getStringCellValue()));
  146 + }
  147 + }
  148 +
  149 + list.add(rowList);
  150 +
  151 + }
  152 + }
  153 + } catch (Exception e) {
  154 + e.printStackTrace();
  155 + return null;
  156 + } finally {
  157 + try {
  158 + if ( wb != null) {
  159 + wb.close();
  160 + }
  161 + if (input != null) {
  162 + input.close();
  163 + }
  164 + } catch (Exception e) {
  165 + }
  166 + }
  167 + return list;
  168 + }
  169 +
  170 +
  171 + public static String getPostfix (String path) {
  172 + if (StringUtils.isBlank(path) || !path.contains(".")) {
  173 + return null;
  174 + }
  175 + return path.substring(path.lastIndexOf(".") + 1, path.length()).trim();
  176 + }
  177 +
  178 +}
@@ -340,6 +340,10 @@ bill.autograph=Autograph @@ -340,6 +340,10 @@ bill.autograph=Autograph
340 bill.check=Check through 340 bill.check=Check through
341 bill.information=Information does not exist 341 bill.information=Information does not exist
342 342
  343 +#主单号修改绑定用户账号
  344 +menu.wbm=Wbm
  345 +wbm.list=Wbm List
  346 +
343 ##### 347 #####
344 billcheck.station=Station 348 billcheck.station=Station
345 billcheck.month=Month 349 billcheck.month=Month
@@ -364,6 +364,11 @@ bill.autograph=\u7b7e\u540d @@ -364,6 +364,11 @@ bill.autograph=\u7b7e\u540d
364 bill.check=\u5236\u5355\u6d4f\u89c8 364 bill.check=\u5236\u5355\u6d4f\u89c8
365 bill.information=\u4fe1\u606f\u4e0d\u5b58\u5728 365 bill.information=\u4fe1\u606f\u4e0d\u5b58\u5728
366 366
  367 +menu.wbm=\u4e3b\u5355\u53f7\u4fee\u6539
  368 +wbm.list=\u4e3b\u5355\u53f7\u4fee\u6539\u5217\u8868
  369 +#wbm.delete=\u522a\u9664
  370 +wbm.loginName=\u7528\u6237\u8d26\u53f7
  371 +
367 handlebill.record=\u5386\u53F2\u529E\u5355\u8BB0\u5F55 372 handlebill.record=\u5386\u53F2\u529E\u5355\u8BB0\u5F55
368 handlebill.agent=\u4EE3\u7406\u4EBA 373 handlebill.agent=\u4EE3\u7406\u4EBA
369 handlebill.flight=\u822A\u73ED\u53F7 374 handlebill.flight=\u822A\u73ED\u53F7
@@ -599,6 +604,7 @@ manifest.delivery=\u4fdd\u5b58\u5e76\u53d1\u9001\u5230\u4ea4\u8fd0 @@ -599,6 +604,7 @@ manifest.delivery=\u4fdd\u5b58\u5e76\u53d1\u9001\u5230\u4ea4\u8fd0
599 manifest.response_text=\u8FD0\u5355\u72B6\u6001 604 manifest.response_text=\u8FD0\u5355\u72B6\u6001
600 manifest.loginaccount=\u7528\u6237\u8d26\u53f7 605 manifest.loginaccount=\u7528\u6237\u8d26\u53f7
601 manifest.agentCode=\u8d27\u4ee3\u4fe1\u606f 606 manifest.agentCode=\u8d27\u4ee3\u4fe1\u606f
  607 +manifest.excel=\u5bfc\u5165\u0045\u0078\u0063\u0065\u006c\u6587\u4ef6
602 608
603 manifest.customs_status_001 = \u666E\u901A\u8D27\u7269 609 manifest.customs_status_001 = \u666E\u901A\u8D27\u7269
604 manifest.customs_status_002 = \u56FD\u9645\u8F6C\u8FD0\u8D27\u7269 610 manifest.customs_status_002 = \u56FD\u9645\u8F6C\u8FD0\u8D27\u7269
  1 +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  2 +<%--
  3 + Created by IntelliJ IDEA.
  4 + User: lenovo
  5 + Date: 2019/3/15
  6 + Time: 16:24
  7 + To change this template use File | Settings | File Templates.
  8 +--%>
  9 +<%@ page contentType="text/html;charset=UTF-8" language="java" %>
  10 +<%
  11 + String path = request.getContextPath();
  12 + String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  13 +%>
  14 +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
  15 +<html>
  16 +<head>
  17 + <title>Title</title>
  18 + <meta charset="utf-8">
  19 + <meta name="viewport" content="width=device-width, initial-scale=1">
  20 + <link href="<%=basePath %>resource/css/base.css" rel="stylesheet">
  21 + <link href="<%=basePath %>resource/css/basic_info.css" rel="stylesheet">
  22 + <link rel="stylesheet" href="<%=basePath %>resource/easyui/uimaker/easyui.css">
  23 + <link href="<%=basePath %>resource/css/form.css" rel="stylesheet">
  24 + <link rel="stylesheet" href="<%=basePath %>resource/css/form.css">
  25 + <script type="text/javascript" src="<%=basePath %>resource/easyui/jquery.min.js"></script>
  26 + <script type="text/javascript" src="<%=basePath %>resource/validate/jquery.validate.js"></script>
  27 + <script type="text/javascript" src="<%=basePath %>resource/validate/validate-extends.js"></script>
  28 +
  29 + <script type="text/javascript" src="<%=basePath %>resource/js/tools.js"></script>
  30 + <!-- validate 验证中英文 -->
  31 + <script type="text/javascript" src="<%=basePath %>resource/validate/jquery.validate-${pageContext.response.locale}.js"></script>
  32 + <script type="text/javascript" src="<%=basePath %>resource/validate/ajaxfileupload.js"></script>
  33 + <script type="text/javascript" src="<%=basePath %>resource/validate/jquery.form.js"></script>
  34 +</head>
  35 +<body>
  36 +<div class="container">
  37 + <div class="content">
  38 + <form class="from-control" id="form">
  39 + <div></div>
  40 + <div>
  41 + <table class="kv-table">
  42 + <tbody>
  43 + <div>
  44 + <tr class="kv-content" >
  45 + <%--<td style="background-color: #EBEDF4; color: black;" class="kv-label" colspan="6"><spring:message code="manifest.excel"/></td>--%>
  46 + <td style="background-color: #EBEDF4; color: black;" class="kv-label" colspan="1">
  47 + <input type="file" id = "file" name = "file" required="required">
  48 + </td>
  49 + <td style="background-color: #EBEDF4; color: black;" class="kv-label" colspan="4">
  50 + <button type="button" class="layui-btn layui-btn-sm layui-icon layui-icon-user" id="subbtn" onclick="submitFrom()">
  51 + <i class="fa fa-trash hidden" aria-hidden="true"></i>导入
  52 + </button>
  53 + </td>
  54 + </tr>
  55 + </div>
  56 + </tbody>
  57 + </table>
  58 + </div>
  59 + </form>
  60 + </div>
  61 +</div>
  62 +
  63 +<script type="text/javascript">
  64 +
  65 +
  66 + function submitFrom() {
  67 + var excelPath = $("#file").val();
  68 + if(excelPath == null || excelPath == ''){
  69 + alert("请选择要上传的Excel文件");
  70 + return;
  71 + }else{
  72 + var fileExtend = excelPath.substring(excelPath.lastIndexOf('.')).toLowerCase();
  73 + if(fileExtend == '.xls' || fileExtend == '.xlsx'){
  74 + $("#form").ajaxSubmit({
  75 + url:"<%=basePath %>manifest/excelUpload",
  76 + cache:false,
  77 + type:'POST',
  78 + dataType:'json',
  79 + success: function(data) {
  80 + if(data.status == 200){
  81 + alert("导入成功");
  82 + window.parent.location.reload();
  83 + var index = parent.layer.getFrameIndex(window.name); // 获取窗口索引
  84 + parent.layer.close(index);
  85 + }else if (data.status == 201){
  86 + alert(data.msg);
  87 + }else {
  88 + alert("网络异常")
  89 + }
  90 + }
  91 + });
  92 + } else {
  93 + alert("文件格式需为'.xls'格式");
  94 + return;
  95 + }
  96 + }
  97 + }
  98 +
  99 +</script>
  100 +</body>
  101 +</html>
@@ -38,6 +38,7 @@ @@ -38,6 +38,7 @@
38 <tr> 38 <tr>
39 <th field="." formatter="editFormat"><spring:message code="opt.edit" /></th> 39 <th field="." formatter="editFormat"><spring:message code="opt.edit" /></th>
40 <th field="loginaccount"><spring:message code="manifest.loginaccount"/></th> 40 <th field="loginaccount"><spring:message code="manifest.loginaccount"/></th>
  41 + <%--货代信息--%>
41 <th field="agentCode"><spring:message code="manifest.agentCode"/></th> 42 <th field="agentCode"><spring:message code="manifest.agentCode"/></th>
42 <th field="waybillnomaster" sortable="true"><spring:message code="manifest.bill.number"/></th> 43 <th field="waybillnomaster" sortable="true"><spring:message code="manifest.bill.number"/></th>
43 <th field="customscode"><spring:message code="manifest.customs"/></th> 44 <th field="customscode"><spring:message code="manifest.customs"/></th>
@@ -60,6 +61,7 @@ @@ -60,6 +61,7 @@
60 <a href="javascript:doSearch()" class="easyui-linkbutton" iconCls="icon-search" data-options="selected:true"><spring:message code="opt.search" /></a> 61 <a href="javascript:doSearch()" class="easyui-linkbutton" iconCls="icon-search" data-options="selected:true"><spring:message code="opt.search" /></a>
61 <a href="javascript:editRow()" class="easyui-linkbutton" style="background:#18A197;color:#FFF;border: 1px solid #18A197;" iconCls="icon-add"><spring:message code="opt.add" /></a> 62 <a href="javascript:editRow()" class="easyui-linkbutton" style="background:#18A197;color:#FFF;border: 1px solid #18A197;" iconCls="icon-add"><spring:message code="opt.add" /></a>
62 <%--<a href="javascript:doDelete()" class="easyui-linkbutton" style="background:red;color:#FFF;border: 1px solid red" iconCls="icon-no"><spring:message code="opt.delete" /></a> --%> 63 <%--<a href="javascript:doDelete()" class="easyui-linkbutton" style="background:red;color:#FFF;border: 1px solid red" iconCls="icon-no"><spring:message code="opt.delete" /></a> --%>
  64 + <a href="javascript:excelUpload()" class="easyui-linkbutton" style="background:#0EA14E;color:#FFF;border: 1px solid #18A197;"><spring:message code="manifest.excel"/></a>
63 </table> 65 </table>
64 </form> 66 </form>
65 </div> 67 </div>
@@ -401,6 +403,19 @@ @@ -401,6 +403,19 @@
401 $("#manifnum").val( $("#manifnum").val()+"-") 403 $("#manifnum").val( $("#manifnum").val()+"-")
402 } 404 }
403 }) 405 })
  406 +
  407 + //导入excel文件
  408 + function excelUpload() {
  409 + // iframe层
  410 + layer.open({
  411 + type : 2,
  412 + title : '导入excel文件',
  413 + maxmin : true,
  414 + shadeClose : false, // 点击遮罩关闭层
  415 + area : [ '450px', '300px' ],
  416 + content : '/manifest/excelView/'
  417 + });
  418 + }
404 </script> 419 </script>
405 </body> 420 </body>
406 </html> 421 </html>
  1 +
  2 +jQuery.extend({
  3 + createUploadIframe: function(id, uri)
  4 + {
  5 + //create frame
  6 + var frameId = 'jUploadFrame' + id;
  7 +
  8 + if(window.ActiveXObject) {
  9 + var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
  10 + if(typeof uri== 'boolean'){
  11 + io.src = 'javascript:false';
  12 + }
  13 + else if(typeof uri== 'string'){
  14 + io.src = uri;
  15 + }
  16 + }
  17 + else {
  18 + var io = document.createElement('iframe');
  19 + io.id = frameId;
  20 + io.name = frameId;
  21 + }
  22 + io.style.position = 'absolute';
  23 + io.style.top = '-1000px';
  24 + io.style.left = '-1000px';
  25 +
  26 + document.body.appendChild(io);
  27 +
  28 + return io
  29 + },
  30 + createUploadForm: function(id, fileElementId)
  31 + {
  32 + //create form
  33 + var formId = 'jUploadForm' + id;
  34 + var fileId = 'jUploadFile' + id;
  35 + var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
  36 + var oldElement = $('#' + fileElementId);
  37 + var newElement = $(oldElement).clone();
  38 + $(oldElement).attr('id', fileId);
  39 + $(oldElement).before(newElement);
  40 + $(oldElement).appendTo(form);
  41 + //set attributes
  42 + $(form).css('position', 'absolute');
  43 + $(form).css('top', '-1200px');
  44 + $(form).css('left', '-1200px');
  45 + $(form).appendTo('body');
  46 + return form;
  47 + },
  48 + addOtherRequestsToForm: function(form,data)
  49 + {
  50 + // add extra parameter
  51 + var originalElement = $('<input type="hidden" name="" value="">');
  52 + for (var key in data) {
  53 + name = key;
  54 + value = data[key];
  55 + var cloneElement = originalElement.clone();
  56 + cloneElement.attr({'name':name,'value':value});
  57 + $(cloneElement).appendTo(form);
  58 + }
  59 + return form;
  60 + },
  61 +
  62 + ajaxFileUpload: function(s) {
  63 + // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
  64 + s = jQuery.extend({}, jQuery.ajaxSettings, s);
  65 + var id = new Date().getTime()
  66 + var form = jQuery.createUploadForm(id, s.fileElementId);
  67 + if ( s.data ) form = jQuery.addOtherRequestsToForm(form,s.data);
  68 + var io = jQuery.createUploadIframe(id, s.secureuri);
  69 + var frameId = 'jUploadFrame' + id;
  70 + var formId = 'jUploadForm' + id;
  71 + // Watch for a new set of requests
  72 + if ( s.global && ! jQuery.active++ )
  73 + {
  74 + jQuery.event.trigger( "ajaxStart" );
  75 + }
  76 + var requestDone = false;
  77 + // Create the request object
  78 + var xml = {}
  79 + if ( s.global )
  80 + jQuery.event.trigger("ajaxSend", [xml, s]);
  81 + // Wait for a response to come back
  82 + var uploadCallback = function(isTimeout)
  83 + {
  84 + var io = document.getElementById(frameId);
  85 + try
  86 + {
  87 + if(io.contentWindow)
  88 + {
  89 + xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
  90 + xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
  91 +
  92 + }else if(io.contentDocument)
  93 + {
  94 + xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;
  95 + xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;
  96 + }
  97 + }catch(e)
  98 + {
  99 + jQuery.handleError(s, xml, null, e);
  100 + }
  101 + if ( xml || isTimeout == "timeout")
  102 + {
  103 + requestDone = true;
  104 + var status;
  105 + try {
  106 + status = isTimeout != "timeout" ? "success" : "error";
  107 + // Make sure that the request was successful or notmodified
  108 + if ( status != "error" )
  109 + {
  110 + // process the data (runs the xml through httpData regardless of callback)
  111 + var data = jQuery.uploadHttpData( xml, s.dataType );
  112 + // If a local callback was specified, fire it and pass it the data
  113 + if ( s.success )
  114 + s.success( data, status );
  115 +
  116 + // Fire the global callback
  117 + if( s.global )
  118 + jQuery.event.trigger( "ajaxSuccess", [xml, s] );
  119 + } else
  120 + jQuery.handleError(s, xml, status);
  121 + } catch(e)
  122 + {
  123 + status = "error";
  124 + jQuery.handleError(s, xml, status, e);
  125 + }
  126 +
  127 + // The request was completed
  128 + if( s.global )
  129 + jQuery.event.trigger( "ajaxComplete", [xml, s] );
  130 +
  131 + // Handle the global AJAX counter
  132 + if ( s.global && ! --jQuery.active )
  133 + jQuery.event.trigger( "ajaxStop" );
  134 +
  135 + // Process result
  136 + if ( s.complete )
  137 + s.complete(xml, status);
  138 +
  139 + jQuery(io).unbind()
  140 +
  141 + setTimeout(function()
  142 + { try
  143 + {
  144 + $(io).remove();
  145 + $(form).remove();
  146 +
  147 + } catch(e)
  148 + {
  149 + jQuery.handleError(s, xml, null, e);
  150 + }
  151 +
  152 + }, 100)
  153 +
  154 + xml = null
  155 +
  156 + }
  157 + }
  158 + // Timeout checker
  159 + if ( s.timeout > 0 )
  160 + {
  161 + setTimeout(function(){
  162 + // Check to see if the request is still happening
  163 + if( !requestDone ) uploadCallback( "timeout" );
  164 + }, s.timeout);
  165 + }
  166 + try
  167 + {
  168 + // var io = $('#' + frameId);
  169 + var form = $('#' + formId);
  170 + $(form).attr('action', s.url);
  171 + $(form).attr('method', 'POST');
  172 + $(form).attr('target', frameId);
  173 + if(form.encoding)
  174 + {
  175 + form.encoding = 'multipart/form-data';
  176 + }
  177 + else
  178 + {
  179 + form.enctype = 'multipart/form-data';
  180 + }
  181 + $(form).submit();
  182 +
  183 + } catch(e)
  184 + {
  185 + jQuery.handleError(s, xml, null, e);
  186 + }
  187 + if(window.attachEvent){
  188 + document.getElementById(frameId).attachEvent('onload', uploadCallback);
  189 + }
  190 + else{
  191 + document.getElementById(frameId).addEventListener('load', uploadCallback, false);
  192 + }
  193 + return {abort: function () {}};
  194 +
  195 + },
  196 +
  197 + uploadHttpData: function( r, type ) {
  198 + var data = !type;
  199 + data = type == "xml" || data ? r.responseXML : r.responseText;
  200 + // If the type is "script", eval it in global context
  201 + if ( type == "script" )
  202 + jQuery.globalEval( data );
  203 + // Get the JavaScript object, if JSON is used.
  204 + if ( type == "json" )
  205 + {
  206 + // If you add mimetype in your response,
  207 + // you have to delete the '<pre></pre>' tag.
  208 + // The pre tag in Chrome has attribute, so have to use regex to remove
  209 + var data = r.responseText;
  210 + var rx = new RegExp("<pre.*?>(.*?)</pre>","i");
  211 + var am = rx.exec(data);
  212 + //this is the desired data extracted
  213 + var data = (am) ? am[1] : ""; //the only submatch or empty
  214 + eval( "data = " + data );
  215 + }
  216 + // evaluate scripts within html
  217 + if ( type == "html" )
  218 + jQuery("<div>").html(data).evalScripts();
  219 + //alert($('param', data).each(function(){alert($(this).attr('value'));}));
  220 + return data;
  221 + },
  222 +
  223 +
  224 + handleError: function( s, xhr, status, e ){
  225 + // If a local callback was specified, fire it
  226 + if ( s.error ) {
  227 + s.error.call( s.context || s, xhr, status, e );
  228 + }
  229 +
  230 + // Fire the global callback
  231 + if ( s.global ) {
  232 + (s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );
  233 + }
  234 + }
  235 +
  236 +})
  237 +
  1 +/*!
  2 + * jQuery Form Plugin
  3 + * version: 3.51.0-2014.06.20
  4 + * Requires jQuery v1.5 or later
  5 + * Copyright (c) 2014 M. Alsup
  6 + * Examples and documentation at: http://malsup.com/jquery/form/
  7 + * Project repository: https://github.com/malsup/form
  8 + * Dual licensed under the MIT and GPL licenses.
  9 + * https://github.com/malsup/form#copyright-and-license
  10 + */
  11 +/*global ActiveXObject */
  12 +
  13 +// AMD support
  14 +(function (factory) {
  15 + "use strict";
  16 + if (typeof define === 'function' && define.amd) {
  17 + // using AMD; register as anon module
  18 + define(['jquery'], factory);
  19 + } else {
  20 + // no AMD; invoke directly
  21 + factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
  22 + }
  23 +}
  24 +
  25 +(function($) {
  26 +"use strict";
  27 +
  28 +/*
  29 + Usage Note:
  30 + -----------
  31 + Do not use both ajaxSubmit and ajaxForm on the same form. These
  32 + functions are mutually exclusive. Use ajaxSubmit if you want
  33 + to bind your own submit handler to the form. For example,
  34 +
  35 + $(document).ready(function() {
  36 + $('#myForm').on('submit', function(e) {
  37 + e.preventDefault(); // <-- important
  38 + $(this).ajaxSubmit({
  39 + target: '#output'
  40 + });
  41 + });
  42 + });
  43 +
  44 + Use ajaxForm when you want the plugin to manage all the event binding
  45 + for you. For example,
  46 +
  47 + $(document).ready(function() {
  48 + $('#myForm').ajaxForm({
  49 + target: '#output'
  50 + });
  51 + });
  52 +
  53 + You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
  54 + form does not have to exist when you invoke ajaxForm:
  55 +
  56 + $('#myForm').ajaxForm({
  57 + delegation: true,
  58 + target: '#output'
  59 + });
  60 +
  61 + When using ajaxForm, the ajaxSubmit function will be invoked for you
  62 + at the appropriate time.
  63 +*/
  64 +
  65 +/**
  66 + * Feature detection
  67 + */
  68 +var feature = {};
  69 +feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
  70 +feature.formdata = window.FormData !== undefined;
  71 +
  72 +var hasProp = !!$.fn.prop;
  73 +
  74 +// attr2 uses prop when it can but checks the return type for
  75 +// an expected string. this accounts for the case where a form
  76 +// contains inputs with names like "action" or "method"; in those
  77 +// cases "prop" returns the element
  78 +$.fn.attr2 = function() {
  79 + if ( ! hasProp ) {
  80 + return this.attr.apply(this, arguments);
  81 + }
  82 + var val = this.prop.apply(this, arguments);
  83 + if ( ( val && val.jquery ) || typeof val === 'string' ) {
  84 + return val;
  85 + }
  86 + return this.attr.apply(this, arguments);
  87 +};
  88 +
  89 +/**
  90 + * ajaxSubmit() provides a mechanism for immediately submitting
  91 + * an HTML form using AJAX.
  92 + */
  93 +$.fn.ajaxSubmit = function(options) {
  94 + /*jshint scripturl:true */
  95 +
  96 + // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
  97 + if (!this.length) {
  98 + log('ajaxSubmit: skipping submit process - no element selected');
  99 + return this;
  100 + }
  101 +
  102 + var method, action, url, $form = this;
  103 +
  104 + if (typeof options == 'function') {
  105 + options = { success: options };
  106 + }
  107 + else if ( options === undefined ) {
  108 + options = {};
  109 + }
  110 +
  111 + method = options.type || this.attr2('method');
  112 + action = options.url || this.attr2('action');
  113 +
  114 + url = (typeof action === 'string') ? $.trim(action) : '';
  115 + url = url || window.location.href || '';
  116 + if (url) {
  117 + // clean url (don't include hash vaue)
  118 + url = (url.match(/^([^#]+)/)||[])[1];
  119 + }
  120 +
  121 + options = $.extend(true, {
  122 + url: url,
  123 + success: $.ajaxSettings.success,
  124 + type: method || $.ajaxSettings.type,
  125 + iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
  126 + }, options);
  127 +
  128 + // hook for manipulating the form data before it is extracted;
  129 + // convenient for use with rich editors like tinyMCE or FCKEditor
  130 + var veto = {};
  131 + this.trigger('form-pre-serialize', [this, options, veto]);
  132 + if (veto.veto) {
  133 + log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
  134 + return this;
  135 + }
  136 +
  137 + // provide opportunity to alter form data before it is serialized
  138 + if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
  139 + log('ajaxSubmit: submit aborted via beforeSerialize callback');
  140 + return this;
  141 + }
  142 +
  143 + var traditional = options.traditional;
  144 + if ( traditional === undefined ) {
  145 + traditional = $.ajaxSettings.traditional;
  146 + }
  147 +
  148 + var elements = [];
  149 + var qx, a = this.formToArray(options.semantic, elements);
  150 + if (options.data) {
  151 + options.extraData = options.data;
  152 + qx = $.param(options.data, traditional);
  153 + }
  154 +
  155 + // give pre-submit callback an opportunity to abort the submit
  156 + if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
  157 + log('ajaxSubmit: submit aborted via beforeSubmit callback');
  158 + return this;
  159 + }
  160 +
  161 + // fire vetoable 'validate' event
  162 + this.trigger('form-submit-validate', [a, this, options, veto]);
  163 + if (veto.veto) {
  164 + log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
  165 + return this;
  166 + }
  167 +
  168 + var q = $.param(a, traditional);
  169 + if (qx) {
  170 + q = ( q ? (q + '&' + qx) : qx );
  171 + }
  172 + if (options.type.toUpperCase() == 'GET') {
  173 + options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
  174 + options.data = null; // data is null for 'get'
  175 + }
  176 + else {
  177 + options.data = q; // data is the query string for 'post'
  178 + }
  179 +
  180 + var callbacks = [];
  181 + if (options.resetForm) {
  182 + callbacks.push(function() { $form.resetForm(); });
  183 + }
  184 + if (options.clearForm) {
  185 + callbacks.push(function() { $form.clearForm(options.includeHidden); });
  186 + }
  187 +
  188 + // perform a load on the target only if dataType is not provided
  189 + if (!options.dataType && options.target) {
  190 + var oldSuccess = options.success || function(){};
  191 + callbacks.push(function(data) {
  192 + var fn = options.replaceTarget ? 'replaceWith' : 'html';
  193 + $(options.target)[fn](data).each(oldSuccess, arguments);
  194 + });
  195 + }
  196 + else if (options.success) {
  197 + callbacks.push(options.success);
  198 + }
  199 +
  200 + options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
  201 + var context = options.context || this ; // jQuery 1.4+ supports scope context
  202 + for (var i=0, max=callbacks.length; i < max; i++) {
  203 + callbacks[i].apply(context, [data, status, xhr || $form, $form]);
  204 + }
  205 + };
  206 +
  207 + if (options.error) {
  208 + var oldError = options.error;
  209 + options.error = function(xhr, status, error) {
  210 + var context = options.context || this;
  211 + oldError.apply(context, [xhr, status, error, $form]);
  212 + };
  213 + }
  214 +
  215 + if (options.complete) {
  216 + var oldComplete = options.complete;
  217 + options.complete = function(xhr, status) {
  218 + var context = options.context || this;
  219 + oldComplete.apply(context, [xhr, status, $form]);
  220 + };
  221 + }
  222 +
  223 + // are there files to upload?
  224 +
  225 + // [value] (issue #113), also see comment:
  226 + // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
  227 + var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
  228 +
  229 + var hasFileInputs = fileInputs.length > 0;
  230 + var mp = 'multipart/form-data';
  231 + var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
  232 +
  233 + var fileAPI = feature.fileapi && feature.formdata;
  234 + log("fileAPI :" + fileAPI);
  235 + var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
  236 +
  237 + var jqxhr;
  238 +
  239 + // options.iframe allows user to force iframe mode
  240 + // 06-NOV-09: now defaulting to iframe mode if file input is detected
  241 + if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
  242 + // hack to fix Safari hang (thanks to Tim Molendijk for this)
  243 + // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
  244 + if (options.closeKeepAlive) {
  245 + $.get(options.closeKeepAlive, function() {
  246 + jqxhr = fileUploadIframe(a);
  247 + });
  248 + }
  249 + else {
  250 + jqxhr = fileUploadIframe(a);
  251 + }
  252 + }
  253 + else if ((hasFileInputs || multipart) && fileAPI) {
  254 + jqxhr = fileUploadXhr(a);
  255 + }
  256 + else {
  257 + jqxhr = $.ajax(options);
  258 + }
  259 +
  260 + $form.removeData('jqxhr').data('jqxhr', jqxhr);
  261 +
  262 + // clear element array
  263 + for (var k=0; k < elements.length; k++) {
  264 + elements[k] = null;
  265 + }
  266 +
  267 + // fire 'notify' event
  268 + this.trigger('form-submit-notify', [this, options]);
  269 + return this;
  270 +
  271 + // utility fn for deep serialization
  272 + function deepSerialize(extraData){
  273 + var serialized = $.param(extraData, options.traditional).split('&');
  274 + var len = serialized.length;
  275 + var result = [];
  276 + var i, part;
  277 + for (i=0; i < len; i++) {
  278 + // #252; undo param space replacement
  279 + serialized[i] = serialized[i].replace(/\+/g,' ');
  280 + part = serialized[i].split('=');
  281 + // #278; use array instead of object storage, favoring array serializations
  282 + result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
  283 + }
  284 + return result;
  285 + }
  286 +
  287 + // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
  288 + function fileUploadXhr(a) {
  289 + var formdata = new FormData();
  290 +
  291 + for (var i=0; i < a.length; i++) {
  292 + formdata.append(a[i].name, a[i].value);
  293 + }
  294 +
  295 + if (options.extraData) {
  296 + var serializedData = deepSerialize(options.extraData);
  297 + for (i=0; i < serializedData.length; i++) {
  298 + if (serializedData[i]) {
  299 + formdata.append(serializedData[i][0], serializedData[i][1]);
  300 + }
  301 + }
  302 + }
  303 +
  304 + options.data = null;
  305 +
  306 + var s = $.extend(true, {}, $.ajaxSettings, options, {
  307 + contentType: false,
  308 + processData: false,
  309 + cache: false,
  310 + type: method || 'POST'
  311 + });
  312 +
  313 + if (options.uploadProgress) {
  314 + // workaround because jqXHR does not expose upload property
  315 + s.xhr = function() {
  316 + var xhr = $.ajaxSettings.xhr();
  317 + if (xhr.upload) {
  318 + xhr.upload.addEventListener('progress', function(event) {
  319 + var percent = 0;
  320 + var position = event.loaded || event.position; /*event.position is deprecated*/
  321 + var total = event.total;
  322 + if (event.lengthComputable) {
  323 + percent = Math.ceil(position / total * 100);
  324 + }
  325 + options.uploadProgress(event, position, total, percent);
  326 + }, false);
  327 + }
  328 + return xhr;
  329 + };
  330 + }
  331 +
  332 + s.data = null;
  333 + var beforeSend = s.beforeSend;
  334 + s.beforeSend = function(xhr, o) {
  335 + //Send FormData() provided by user
  336 + if (options.formData) {
  337 + o.data = options.formData;
  338 + }
  339 + else {
  340 + o.data = formdata;
  341 + }
  342 + if(beforeSend) {
  343 + beforeSend.call(this, xhr, o);
  344 + }
  345 + };
  346 + return $.ajax(s);
  347 + }
  348 +
  349 + // private function for handling file uploads (hat tip to YAHOO!)
  350 + function fileUploadIframe(a) {
  351 + var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
  352 + var deferred = $.Deferred();
  353 +
  354 + // #341
  355 + deferred.abort = function(status) {
  356 + xhr.abort(status);
  357 + };
  358 +
  359 + if (a) {
  360 + // ensure that every serialized input is still enabled
  361 + for (i=0; i < elements.length; i++) {
  362 + el = $(elements[i]);
  363 + if ( hasProp ) {
  364 + el.prop('disabled', false);
  365 + }
  366 + else {
  367 + el.removeAttr('disabled');
  368 + }
  369 + }
  370 + }
  371 +
  372 + s = $.extend(true, {}, $.ajaxSettings, options);
  373 + s.context = s.context || s;
  374 + id = 'jqFormIO' + (new Date().getTime());
  375 + if (s.iframeTarget) {
  376 + $io = $(s.iframeTarget);
  377 + n = $io.attr2('name');
  378 + if (!n) {
  379 + $io.attr2('name', id);
  380 + }
  381 + else {
  382 + id = n;
  383 + }
  384 + }
  385 + else {
  386 + $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
  387 + $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
  388 + }
  389 + io = $io[0];
  390 +
  391 +
  392 + xhr = { // mock object
  393 + aborted: 0,
  394 + responseText: null,
  395 + responseXML: null,
  396 + status: 0,
  397 + statusText: 'n/a',
  398 + getAllResponseHeaders: function() {},
  399 + getResponseHeader: function() {},
  400 + setRequestHeader: function() {},
  401 + abort: function(status) {
  402 + var e = (status === 'timeout' ? 'timeout' : 'aborted');
  403 + log('aborting upload... ' + e);
  404 + this.aborted = 1;
  405 +
  406 + try { // #214, #257
  407 + if (io.contentWindow.document.execCommand) {
  408 + io.contentWindow.document.execCommand('Stop');
  409 + }
  410 + }
  411 + catch(ignore) {}
  412 +
  413 + $io.attr('src', s.iframeSrc); // abort op in progress
  414 + xhr.error = e;
  415 + if (s.error) {
  416 + s.error.call(s.context, xhr, e, status);
  417 + }
  418 + if (g) {
  419 + $.event.trigger("ajaxError", [xhr, s, e]);
  420 + }
  421 + if (s.complete) {
  422 + s.complete.call(s.context, xhr, e);
  423 + }
  424 + }
  425 + };
  426 +
  427 + g = s.global;
  428 + // trigger ajax global events so that activity/block indicators work like normal
  429 + if (g && 0 === $.active++) {
  430 + $.event.trigger("ajaxStart");
  431 + }
  432 + if (g) {
  433 + $.event.trigger("ajaxSend", [xhr, s]);
  434 + }
  435 +
  436 + if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
  437 + if (s.global) {
  438 + $.active--;
  439 + }
  440 + deferred.reject();
  441 + return deferred;
  442 + }
  443 + if (xhr.aborted) {
  444 + deferred.reject();
  445 + return deferred;
  446 + }
  447 +
  448 + // add submitting element to data if we know it
  449 + sub = form.clk;
  450 + if (sub) {
  451 + n = sub.name;
  452 + if (n && !sub.disabled) {
  453 + s.extraData = s.extraData || {};
  454 + s.extraData[n] = sub.value;
  455 + if (sub.type == "image") {
  456 + s.extraData[n+'.x'] = form.clk_x;
  457 + s.extraData[n+'.y'] = form.clk_y;
  458 + }
  459 + }
  460 + }
  461 +
  462 + var CLIENT_TIMEOUT_ABORT = 1;
  463 + var SERVER_ABORT = 2;
  464 +
  465 + function getDoc(frame) {
  466 + /* it looks like contentWindow or contentDocument do not
  467 + * carry the protocol property in ie8, when running under ssl
  468 + * frame.document is the only valid response document, since
  469 + * the protocol is know but not on the other two objects. strange?
  470 + * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
  471 + */
  472 +
  473 + var doc = null;
  474 +
  475 + // IE8 cascading access check
  476 + try {
  477 + if (frame.contentWindow) {
  478 + doc = frame.contentWindow.document;
  479 + }
  480 + } catch(err) {
  481 + // IE8 access denied under ssl & missing protocol
  482 + log('cannot get iframe.contentWindow document: ' + err);
  483 + }
  484 +
  485 + if (doc) { // successful getting content
  486 + return doc;
  487 + }
  488 +
  489 + try { // simply checking may throw in ie8 under ssl or mismatched protocol
  490 + doc = frame.contentDocument ? frame.contentDocument : frame.document;
  491 + } catch(err) {
  492 + // last attempt
  493 + log('cannot get iframe.contentDocument: ' + err);
  494 + doc = frame.document;
  495 + }
  496 + return doc;
  497 + }
  498 +
  499 + // Rails CSRF hack (thanks to Yvan Barthelemy)
  500 + var csrf_token = $('meta[name=csrf-token]').attr('content');
  501 + var csrf_param = $('meta[name=csrf-param]').attr('content');
  502 + if (csrf_param && csrf_token) {
  503 + s.extraData = s.extraData || {};
  504 + s.extraData[csrf_param] = csrf_token;
  505 + }
  506 +
  507 + // take a breath so that pending repaints get some cpu time before the upload starts
  508 + function doSubmit() {
  509 + // make sure form attrs are set
  510 + var t = $form.attr2('target'),
  511 + a = $form.attr2('action'),
  512 + mp = 'multipart/form-data',
  513 + et = $form.attr('enctype') || $form.attr('encoding') || mp;
  514 +
  515 + // update form attrs in IE friendly way
  516 + form.setAttribute('target',id);
  517 + if (!method || /post/i.test(method) ) {
  518 + form.setAttribute('method', 'POST');
  519 + }
  520 + if (a != s.url) {
  521 + form.setAttribute('action', s.url);
  522 + }
  523 +
  524 + // ie borks in some cases when setting encoding
  525 + if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
  526 + $form.attr({
  527 + encoding: 'multipart/form-data',
  528 + enctype: 'multipart/form-data'
  529 + });
  530 + }
  531 +
  532 + // support timout
  533 + if (s.timeout) {
  534 + timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
  535 + }
  536 +
  537 + // look for server aborts
  538 + function checkState() {
  539 + try {
  540 + var state = getDoc(io).readyState;
  541 + log('state = ' + state);
  542 + if (state && state.toLowerCase() == 'uninitialized') {
  543 + setTimeout(checkState,50);
  544 + }
  545 + }
  546 + catch(e) {
  547 + log('Server abort: ' , e, ' (', e.name, ')');
  548 + cb(SERVER_ABORT);
  549 + if (timeoutHandle) {
  550 + clearTimeout(timeoutHandle);
  551 + }
  552 + timeoutHandle = undefined;
  553 + }
  554 + }
  555 +
  556 + // add "extra" data to form if provided in options
  557 + var extraInputs = [];
  558 + try {
  559 + if (s.extraData) {
  560 + for (var n in s.extraData) {
  561 + if (s.extraData.hasOwnProperty(n)) {
  562 + // if using the $.param format that allows for multiple values with the same name
  563 + if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
  564 + extraInputs.push(
  565 + $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value)
  566 + .appendTo(form)[0]);
  567 + } else {
  568 + extraInputs.push(
  569 + $('<input type="hidden" name="'+n+'">').val(s.extraData[n])
  570 + .appendTo(form)[0]);
  571 + }
  572 + }
  573 + }
  574 + }
  575 +
  576 + if (!s.iframeTarget) {
  577 + // add iframe to doc and submit the form
  578 + $io.appendTo('body');
  579 + }
  580 + if (io.attachEvent) {
  581 + io.attachEvent('onload', cb);
  582 + }
  583 + else {
  584 + io.addEventListener('load', cb, false);
  585 + }
  586 + setTimeout(checkState,15);
  587 +
  588 + try {
  589 + form.submit();
  590 + } catch(err) {
  591 + // just in case form has element with name/id of 'submit'
  592 + var submitFn = document.createElement('form').submit;
  593 + submitFn.apply(form);
  594 + }
  595 + }
  596 + finally {
  597 + // reset attrs and remove "extra" input elements
  598 + form.setAttribute('action',a);
  599 + form.setAttribute('enctype', et); // #380
  600 + if(t) {
  601 + form.setAttribute('target', t);
  602 + } else {
  603 + $form.removeAttr('target');
  604 + }
  605 + $(extraInputs).remove();
  606 + }
  607 + }
  608 +
  609 + if (s.forceSync) {
  610 + doSubmit();
  611 + }
  612 + else {
  613 + setTimeout(doSubmit, 10); // this lets dom updates render
  614 + }
  615 +
  616 + var data, doc, domCheckCount = 50, callbackProcessed;
  617 +
  618 + function cb(e) {
  619 + if (xhr.aborted || callbackProcessed) {
  620 + return;
  621 + }
  622 +
  623 + doc = getDoc(io);
  624 + if(!doc) {
  625 + log('cannot access response document');
  626 + e = SERVER_ABORT;
  627 + }
  628 + if (e === CLIENT_TIMEOUT_ABORT && xhr) {
  629 + xhr.abort('timeout');
  630 + deferred.reject(xhr, 'timeout');
  631 + return;
  632 + }
  633 + else if (e == SERVER_ABORT && xhr) {
  634 + xhr.abort('server abort');
  635 + deferred.reject(xhr, 'error', 'server abort');
  636 + return;
  637 + }
  638 +
  639 + if (!doc || doc.location.href == s.iframeSrc) {
  640 + // response not received yet
  641 + if (!timedOut) {
  642 + return;
  643 + }
  644 + }
  645 + if (io.detachEvent) {
  646 + io.detachEvent('onload', cb);
  647 + }
  648 + else {
  649 + io.removeEventListener('load', cb, false);
  650 + }
  651 +
  652 + var status = 'success', errMsg;
  653 + try {
  654 + if (timedOut) {
  655 + throw 'timeout';
  656 + }
  657 +
  658 + var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
  659 + log('isXml='+isXml);
  660 + if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
  661 + if (--domCheckCount) {
  662 + // in some browsers (Opera) the iframe DOM is not always traversable when
  663 + // the onload callback fires, so we loop a bit to accommodate
  664 + log('requeing onLoad callback, DOM not available');
  665 + setTimeout(cb, 250);
  666 + return;
  667 + }
  668 + // let this fall through because server response could be an empty document
  669 + //log('Could not access iframe DOM after mutiple tries.');
  670 + //throw 'DOMException: not available';
  671 + }
  672 +
  673 + //log('response detected');
  674 + var docRoot = doc.body ? doc.body : doc.documentElement;
  675 + xhr.responseText = docRoot ? docRoot.innerHTML : null;
  676 + xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
  677 + if (isXml) {
  678 + s.dataType = 'xml';
  679 + }
  680 + xhr.getResponseHeader = function(header){
  681 + var headers = {'content-type': s.dataType};
  682 + return headers[header.toLowerCase()];
  683 + };
  684 + // support for XHR 'status' & 'statusText' emulation :
  685 + if (docRoot) {
  686 + xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
  687 + xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
  688 + }
  689 +
  690 + var dt = (s.dataType || '').toLowerCase();
  691 + var scr = /(json|script|text)/.test(dt);
  692 + if (scr || s.textarea) {
  693 + // see if user embedded response in textarea
  694 + var ta = doc.getElementsByTagName('textarea')[0];
  695 + if (ta) {
  696 + xhr.responseText = ta.value;
  697 + // support for XHR 'status' & 'statusText' emulation :
  698 + xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
  699 + xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
  700 + }
  701 + else if (scr) {
  702 + // account for browsers injecting pre around json response
  703 + var pre = doc.getElementsByTagName('pre')[0];
  704 + var b = doc.getElementsByTagName('body')[0];
  705 + if (pre) {
  706 + xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
  707 + }
  708 + else if (b) {
  709 + xhr.responseText = b.textContent ? b.textContent : b.innerText;
  710 + }
  711 + }
  712 + }
  713 + else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
  714 + xhr.responseXML = toXml(xhr.responseText);
  715 + }
  716 +
  717 + try {
  718 + data = httpData(xhr, dt, s);
  719 + }
  720 + catch (err) {
  721 + status = 'parsererror';
  722 + xhr.error = errMsg = (err || status);
  723 + }
  724 + }
  725 + catch (err) {
  726 + log('error caught: ',err);
  727 + status = 'error';
  728 + xhr.error = errMsg = (err || status);
  729 + }
  730 +
  731 + if (xhr.aborted) {
  732 + log('upload aborted');
  733 + status = null;
  734 + }
  735 +
  736 + if (xhr.status) { // we've set xhr.status
  737 + status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
  738 + }
  739 +
  740 + // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
  741 + if (status === 'success') {
  742 + if (s.success) {
  743 + s.success.call(s.context, data, 'success', xhr);
  744 + }
  745 + deferred.resolve(xhr.responseText, 'success', xhr);
  746 + if (g) {
  747 + $.event.trigger("ajaxSuccess", [xhr, s]);
  748 + }
  749 + }
  750 + else if (status) {
  751 + if (errMsg === undefined) {
  752 + errMsg = xhr.statusText;
  753 + }
  754 + if (s.error) {
  755 + s.error.call(s.context, xhr, status, errMsg);
  756 + }
  757 + deferred.reject(xhr, 'error', errMsg);
  758 + if (g) {
  759 + $.event.trigger("ajaxError", [xhr, s, errMsg]);
  760 + }
  761 + }
  762 +
  763 + if (g) {
  764 + $.event.trigger("ajaxComplete", [xhr, s]);
  765 + }
  766 +
  767 + if (g && ! --$.active) {
  768 + $.event.trigger("ajaxStop");
  769 + }
  770 +
  771 + if (s.complete) {
  772 + s.complete.call(s.context, xhr, status);
  773 + }
  774 +
  775 + callbackProcessed = true;
  776 + if (s.timeout) {
  777 + clearTimeout(timeoutHandle);
  778 + }
  779 +
  780 + // clean up
  781 + setTimeout(function() {
  782 + if (!s.iframeTarget) {
  783 + $io.remove();
  784 + }
  785 + else { //adding else to clean up existing iframe response.
  786 + $io.attr('src', s.iframeSrc);
  787 + }
  788 + xhr.responseXML = null;
  789 + }, 100);
  790 + }
  791 +
  792 + var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
  793 + if (window.ActiveXObject) {
  794 + doc = new ActiveXObject('Microsoft.XMLDOM');
  795 + doc.async = 'false';
  796 + doc.loadXML(s);
  797 + }
  798 + else {
  799 + doc = (new DOMParser()).parseFromString(s, 'text/xml');
  800 + }
  801 + return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
  802 + };
  803 + var parseJSON = $.parseJSON || function(s) {
  804 + /*jslint evil:true */
  805 + return window['eval']('(' + s + ')');
  806 + };
  807 +
  808 + var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
  809 +
  810 + var ct = xhr.getResponseHeader('content-type') || '',
  811 + xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
  812 + data = xml ? xhr.responseXML : xhr.responseText;
  813 +
  814 + if (xml && data.documentElement.nodeName === 'parsererror') {
  815 + if ($.error) {
  816 + $.error('parsererror');
  817 + }
  818 + }
  819 + if (s && s.dataFilter) {
  820 + data = s.dataFilter(data, type);
  821 + }
  822 + if (typeof data === 'string') {
  823 + if (type === 'json' || !type && ct.indexOf('json') >= 0) {
  824 + data = parseJSON(data);
  825 + } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
  826 + $.globalEval(data);
  827 + }
  828 + }
  829 + return data;
  830 + };
  831 +
  832 + return deferred;
  833 + }
  834 +};
  835 +
  836 +/**
  837 + * ajaxForm() provides a mechanism for fully automating form submission.
  838 + *
  839 + * The advantages of using this method instead of ajaxSubmit() are:
  840 + *
  841 + * 1: This method will include coordinates for <input type="image" /> elements (if the element
  842 + * is used to submit the form).
  843 + * 2. This method will include the submit element's name/value data (for the element that was
  844 + * used to submit the form).
  845 + * 3. This method binds the submit() method to the form for you.
  846 + *
  847 + * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
  848 + * passes the options argument along after properly binding events for submit elements and
  849 + * the form itself.
  850 + */
  851 +$.fn.ajaxForm = function(options) {
  852 + options = options || {};
  853 + options.delegation = options.delegation && $.isFunction($.fn.on);
  854 +
  855 + // in jQuery 1.3+ we can fix mistakes with the ready state
  856 + if (!options.delegation && this.length === 0) {
  857 + var o = { s: this.selector, c: this.context };
  858 + if (!$.isReady && o.s) {
  859 + log('DOM not ready, queuing ajaxForm');
  860 + $(function() {
  861 + $(o.s,o.c).ajaxForm(options);
  862 + });
  863 + return this;
  864 + }
  865 + // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
  866 + log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
  867 + return this;
  868 + }
  869 +
  870 + if ( options.delegation ) {
  871 + $(document)
  872 + .off('submit.form-plugin', this.selector, doAjaxSubmit)
  873 + .off('click.form-plugin', this.selector, captureSubmittingElement)
  874 + .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
  875 + .on('click.form-plugin', this.selector, options, captureSubmittingElement);
  876 + return this;
  877 + }
  878 +
  879 + return this.ajaxFormUnbind()
  880 + .bind('submit.form-plugin', options, doAjaxSubmit)
  881 + .bind('click.form-plugin', options, captureSubmittingElement);
  882 +};
  883 +
  884 +// private event handlers
  885 +function doAjaxSubmit(e) {
  886 + /*jshint validthis:true */
  887 + var options = e.data;
  888 + if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
  889 + e.preventDefault();
  890 + $(e.target).ajaxSubmit(options); // #365
  891 + }
  892 +}
  893 +
  894 +function captureSubmittingElement(e) {
  895 + /*jshint validthis:true */
  896 + var target = e.target;
  897 + var $el = $(target);
  898 + if (!($el.is("[type=submit],[type=image]"))) {
  899 + // is this a child element of the submit el? (ex: a span within a button)
  900 + var t = $el.closest('[type=submit]');
  901 + if (t.length === 0) {
  902 + return;
  903 + }
  904 + target = t[0];
  905 + }
  906 + var form = this;
  907 + form.clk = target;
  908 + if (target.type == 'image') {
  909 + if (e.offsetX !== undefined) {
  910 + form.clk_x = e.offsetX;
  911 + form.clk_y = e.offsetY;
  912 + } else if (typeof $.fn.offset == 'function') {
  913 + var offset = $el.offset();
  914 + form.clk_x = e.pageX - offset.left;
  915 + form.clk_y = e.pageY - offset.top;
  916 + } else {
  917 + form.clk_x = e.pageX - target.offsetLeft;
  918 + form.clk_y = e.pageY - target.offsetTop;
  919 + }
  920 + }
  921 + // clear form vars
  922 + setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
  923 +}
  924 +
  925 +
  926 +// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
  927 +$.fn.ajaxFormUnbind = function() {
  928 + return this.unbind('submit.form-plugin click.form-plugin');
  929 +};
  930 +
  931 +/**
  932 + * formToArray() gathers form element data into an array of objects that can
  933 + * be passed to any of the following ajax functions: $.get, $.post, or load.
  934 + * Each object in the array has both a 'name' and 'value' property. An example of
  935 + * an array for a simple login form might be:
  936 + *
  937 + * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
  938 + *
  939 + * It is this array that is passed to pre-submit callback functions provided to the
  940 + * ajaxSubmit() and ajaxForm() methods.
  941 + */
  942 +$.fn.formToArray = function(semantic, elements) {
  943 + var a = [];
  944 + if (this.length === 0) {
  945 + return a;
  946 + }
  947 +
  948 + var form = this[0];
  949 + var formId = this.attr('id');
  950 + var els = semantic ? form.getElementsByTagName('*') : form.elements;
  951 + var els2;
  952 +
  953 + if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
  954 + els = $(els).get(); // convert to standard array
  955 + }
  956 +
  957 + // #386; account for inputs outside the form which use the 'form' attribute
  958 + if ( formId ) {
  959 + els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet
  960 + if ( els2.length ) {
  961 + els = (els || []).concat(els2);
  962 + }
  963 + }
  964 +
  965 + if (!els || !els.length) {
  966 + return a;
  967 + }
  968 +
  969 + var i,j,n,v,el,max,jmax;
  970 + for(i=0, max=els.length; i < max; i++) {
  971 + el = els[i];
  972 + n = el.name;
  973 + if (!n || el.disabled) {
  974 + continue;
  975 + }
  976 +
  977 + if (semantic && form.clk && el.type == "image") {
  978 + // handle image inputs on the fly when semantic == true
  979 + if(form.clk == el) {
  980 + a.push({name: n, value: $(el).val(), type: el.type });
  981 + a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  982 + }
  983 + continue;
  984 + }
  985 +
  986 + v = $.fieldValue(el, true);
  987 + if (v && v.constructor == Array) {
  988 + if (elements) {
  989 + elements.push(el);
  990 + }
  991 + for(j=0, jmax=v.length; j < jmax; j++) {
  992 + a.push({name: n, value: v[j]});
  993 + }
  994 + }
  995 + else if (feature.fileapi && el.type == 'file') {
  996 + if (elements) {
  997 + elements.push(el);
  998 + }
  999 + var files = el.files;
  1000 + if (files.length) {
  1001 + for (j=0; j < files.length; j++) {
  1002 + a.push({name: n, value: files[j], type: el.type});
  1003 + }
  1004 + }
  1005 + else {
  1006 + // #180
  1007 + a.push({ name: n, value: '', type: el.type });
  1008 + }
  1009 + }
  1010 + else if (v !== null && typeof v != 'undefined') {
  1011 + if (elements) {
  1012 + elements.push(el);
  1013 + }
  1014 + a.push({name: n, value: v, type: el.type, required: el.required});
  1015 + }
  1016 + }
  1017 +
  1018 + if (!semantic && form.clk) {
  1019 + // input type=='image' are not found in elements array! handle it here
  1020 + var $input = $(form.clk), input = $input[0];
  1021 + n = input.name;
  1022 + if (n && !input.disabled && input.type == 'image') {
  1023 + a.push({name: n, value: $input.val()});
  1024 + a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  1025 + }
  1026 + }
  1027 + return a;
  1028 +};
  1029 +
  1030 +/**
  1031 + * Serializes form data into a 'submittable' string. This method will return a string
  1032 + * in the format: name1=value1&amp;name2=value2
  1033 + */
  1034 +$.fn.formSerialize = function(semantic) {
  1035 + //hand off to jQuery.param for proper encoding
  1036 + return $.param(this.formToArray(semantic));
  1037 +};
  1038 +
  1039 +/**
  1040 + * Serializes all field elements in the jQuery object into a query string.
  1041 + * This method will return a string in the format: name1=value1&amp;name2=value2
  1042 + */
  1043 +$.fn.fieldSerialize = function(successful) {
  1044 + var a = [];
  1045 + this.each(function() {
  1046 + var n = this.name;
  1047 + if (!n) {
  1048 + return;
  1049 + }
  1050 + var v = $.fieldValue(this, successful);
  1051 + if (v && v.constructor == Array) {
  1052 + for (var i=0,max=v.length; i < max; i++) {
  1053 + a.push({name: n, value: v[i]});
  1054 + }
  1055 + }
  1056 + else if (v !== null && typeof v != 'undefined') {
  1057 + a.push({name: this.name, value: v});
  1058 + }
  1059 + });
  1060 + //hand off to jQuery.param for proper encoding
  1061 + return $.param(a);
  1062 +};
  1063 +
  1064 +/**
  1065 + * Returns the value(s) of the element in the matched set. For example, consider the following form:
  1066 + *
  1067 + * <form><fieldset>
  1068 + * <input name="A" type="text" />
  1069 + * <input name="A" type="text" />
  1070 + * <input name="B" type="checkbox" value="B1" />
  1071 + * <input name="B" type="checkbox" value="B2"/>
  1072 + * <input name="C" type="radio" value="C1" />
  1073 + * <input name="C" type="radio" value="C2" />
  1074 + * </fieldset></form>
  1075 + *
  1076 + * var v = $('input[type=text]').fieldValue();
  1077 + * // if no values are entered into the text inputs
  1078 + * v == ['','']
  1079 + * // if values entered into the text inputs are 'foo' and 'bar'
  1080 + * v == ['foo','bar']
  1081 + *
  1082 + * var v = $('input[type=checkbox]').fieldValue();
  1083 + * // if neither checkbox is checked
  1084 + * v === undefined
  1085 + * // if both checkboxes are checked
  1086 + * v == ['B1', 'B2']
  1087 + *
  1088 + * var v = $('input[type=radio]').fieldValue();
  1089 + * // if neither radio is checked
  1090 + * v === undefined
  1091 + * // if first radio is checked
  1092 + * v == ['C1']
  1093 + *
  1094 + * The successful argument controls whether or not the field element must be 'successful'
  1095 + * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  1096 + * The default value of the successful argument is true. If this value is false the value(s)
  1097 + * for each element is returned.
  1098 + *
  1099 + * Note: This method *always* returns an array. If no valid value can be determined the
  1100 + * array will be empty, otherwise it will contain one or more values.
  1101 + */
  1102 +$.fn.fieldValue = function(successful) {
  1103 + for (var val=[], i=0, max=this.length; i < max; i++) {
  1104 + var el = this[i];
  1105 + var v = $.fieldValue(el, successful);
  1106 + if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
  1107 + continue;
  1108 + }
  1109 + if (v.constructor == Array) {
  1110 + $.merge(val, v);
  1111 + }
  1112 + else {
  1113 + val.push(v);
  1114 + }
  1115 + }
  1116 + return val;
  1117 +};
  1118 +
  1119 +/**
  1120 + * Returns the value of the field element.
  1121 + */
  1122 +$.fieldValue = function(el, successful) {
  1123 + var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
  1124 + if (successful === undefined) {
  1125 + successful = true;
  1126 + }
  1127 +
  1128 + if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
  1129 + (t == 'checkbox' || t == 'radio') && !el.checked ||
  1130 + (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
  1131 + tag == 'select' && el.selectedIndex == -1)) {
  1132 + return null;
  1133 + }
  1134 +
  1135 + if (tag == 'select') {
  1136 + var index = el.selectedIndex;
  1137 + if (index < 0) {
  1138 + return null;
  1139 + }
  1140 + var a = [], ops = el.options;
  1141 + var one = (t == 'select-one');
  1142 + var max = (one ? index+1 : ops.length);
  1143 + for(var i=(one ? index : 0); i < max; i++) {
  1144 + var op = ops[i];
  1145 + if (op.selected) {
  1146 + var v = op.value;
  1147 + if (!v) { // extra pain for IE...
  1148 + v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
  1149 + }
  1150 + if (one) {
  1151 + return v;
  1152 + }
  1153 + a.push(v);
  1154 + }
  1155 + }
  1156 + return a;
  1157 + }
  1158 + return $(el).val();
  1159 +};
  1160 +
  1161 +/**
  1162 + * Clears the form data. Takes the following actions on the form's input fields:
  1163 + * - input text fields will have their 'value' property set to the empty string
  1164 + * - select elements will have their 'selectedIndex' property set to -1
  1165 + * - checkbox and radio inputs will have their 'checked' property set to false
  1166 + * - inputs of type submit, button, reset, and hidden will *not* be effected
  1167 + * - button elements will *not* be effected
  1168 + */
  1169 +$.fn.clearForm = function(includeHidden) {
  1170 + return this.each(function() {
  1171 + $('input,select,textarea', this).clearFields(includeHidden);
  1172 + });
  1173 +};
  1174 +
  1175 +/**
  1176 + * Clears the selected form elements.
  1177 + */
  1178 +$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
  1179 + var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
  1180 + return this.each(function() {
  1181 + var t = this.type, tag = this.tagName.toLowerCase();
  1182 + if (re.test(t) || tag == 'textarea') {
  1183 + this.value = '';
  1184 + }
  1185 + else if (t == 'checkbox' || t == 'radio') {
  1186 + this.checked = false;
  1187 + }
  1188 + else if (tag == 'select') {
  1189 + this.selectedIndex = -1;
  1190 + }
  1191 + else if (t == "file") {
  1192 + if (/MSIE/.test(navigator.userAgent)) {
  1193 + $(this).replaceWith($(this).clone(true));
  1194 + } else {
  1195 + $(this).val('');
  1196 + }
  1197 + }
  1198 + else if (includeHidden) {
  1199 + // includeHidden can be the value true, or it can be a selector string
  1200 + // indicating a special test; for example:
  1201 + // $('#myForm').clearForm('.special:hidden')
  1202 + // the above would clean hidden inputs that have the class of 'special'
  1203 + if ( (includeHidden === true && /hidden/.test(t)) ||
  1204 + (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {
  1205 + this.value = '';
  1206 + }
  1207 + }
  1208 + });
  1209 +};
  1210 +
  1211 +/**
  1212 + * Resets the form data. Causes all form elements to be reset to their original value.
  1213 + */
  1214 +$.fn.resetForm = function() {
  1215 + return this.each(function() {
  1216 + // guard against an input with the name of 'reset'
  1217 + // note that IE reports the reset function as an 'object'
  1218 + if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
  1219 + this.reset();
  1220 + }
  1221 + });
  1222 +};
  1223 +
  1224 +/**
  1225 + * Enables or disables any matching elements.
  1226 + */
  1227 +$.fn.enable = function(b) {
  1228 + if (b === undefined) {
  1229 + b = true;
  1230 + }
  1231 + return this.each(function() {
  1232 + this.disabled = !b;
  1233 + });
  1234 +};
  1235 +
  1236 +/**
  1237 + * Checks/unchecks any matching checkboxes or radio buttons and
  1238 + * selects/deselects and matching option elements.
  1239 + */
  1240 +$.fn.selected = function(select) {
  1241 + if (select === undefined) {
  1242 + select = true;
  1243 + }
  1244 + return this.each(function() {
  1245 + var t = this.type;
  1246 + if (t == 'checkbox' || t == 'radio') {
  1247 + this.checked = select;
  1248 + }
  1249 + else if (this.tagName.toLowerCase() == 'option') {
  1250 + var $sel = $(this).parent('select');
  1251 + if (select && $sel[0] && $sel[0].type == 'select-one') {
  1252 + // deselect all other options
  1253 + $sel.find('option').selected(false);
  1254 + }
  1255 + this.selected = select;
  1256 + }
  1257 + });
  1258 +};
  1259 +
  1260 +// expose debug var
  1261 +$.fn.ajaxSubmit.debug = false;
  1262 +
  1263 +// helper fn for console logging
  1264 +function log() {
  1265 + if (!$.fn.ajaxSubmit.debug) {
  1266 + return;
  1267 + }
  1268 + var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
  1269 + if (window.console && window.console.log) {
  1270 + window.console.log(msg);
  1271 + }
  1272 + else if (window.opera && window.opera.postError) {
  1273 + window.opera.postError(msg);
  1274 + }
  1275 +}
  1276 +
  1277 +}));