diff --git a/App_Code/authToken.cs b/App_Code/authToken.cs index 58e2a13..3fa3b2a 100644 --- a/App_Code/authToken.cs +++ b/App_Code/authToken.cs @@ -31,7 +31,7 @@ public class authToken conn.Execute("delete token where token_expireddate <= @token_expireddate", new { token_expireddate = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") }); HttpCookie tokenCookie = (HttpContext.Current.Request.Cookies["token"] == null) ? null : HttpContext.Current.Request.Cookies["token"]; - HttpCookie idCookie = (HttpContext.Current.Request.Cookies["id"] == null) ? null : HttpContext.Current.Request.Cookies["id"]; + //HttpCookie idCookie = (HttpContext.Current.Request.Cookies["id"] == null) ? null : HttpContext.Current.Request.Cookies["id"]; if (tokenCookie == null) { @@ -56,12 +56,12 @@ public class authToken return; } else { - idCookie.Expires = DateTime.Now.AddMinutes(60); + //idCookie.Expires = DateTime.Now.AddMinutes(60); tokenCookie.Expires = DateTime.Now.AddDays(10); HttpContext.Current.Response.Cookies.Add(tokenCookie); - HttpContext.Current.Response.Cookies.Add(idCookie); + //HttpContext.Current.Response.Cookies.Add(idCookie); } loginToken.token_expireddate = DateTime.Now.AddMinutes(60); diff --git a/App_Code/dbClass.cs b/App_Code/dbClass.cs index 40848ce..02ec331 100644 --- a/App_Code/dbClass.cs +++ b/App_Code/dbClass.cs @@ -6,6 +6,40 @@ using System.Collections.Generic; using System.Linq; using System.Web; +[Table("babyDataRecView")] +public class babyDataRecView +{ + [JsonIgnore] + [Key] + public int lineUser_sn { get; set; } = 0; + public string lineUser_uid { get; set; } = ""; + public string line_uid { get; set; } = ""; + public string line_displayName { get; set; } = ""; + public DateTime lineUser_createdate { get; set; } = DateTime.Now; + public DateTime lineUser_modifydate { get; set; } = DateTime.Now; + public string babyData_uid { get; set; } = ""; + public string babyData_name { get; set; } = ""; + public DateTime babyData_birthday { get; set; } = DateTime.Now; + public string babyData_sexual { get; set; } = ""; + public string babyData_bindedLine { get; set; } = ""; + public DateTime babyData_createdate { get; set; } = DateTime.Now; + public DateTime babyData_bindeddate { get; set; } = DateTime.Now; + public DateTime babyData_lastTestDate { get; set; } = DateTime.Now; + public string babyRec_uid { get; set; } = ""; + public string babyRec_key { get; set; } = ""; + public double babyRec_height { get; set; } = 0; + public double babyRec_inpercent { get; set; } = 0; + public double babyRec_middleHeight { get; set; } = 0; + public DateTime babyRec_recdate { get; set; } = DateTime.Now; + public int babyRec_recYear { get; set; } = 0; + public int babyRec_recMonth { get; set; } = 0; + public int babyRec_recDay { get; set; } = 0; + public int babyRec_months { get; set; } = 0; + public string babyRec_monthLastRec { get; set; } = "N"; + public string babyRec_newestRec { get; set; } = "N"; + public string babyRec_yearMonthStr { get; set; } = ""; +} + [Table("babyRec")] public class babyRec { @@ -45,6 +79,7 @@ public class babyData public string babyData_bindedLine { get; set; } = ""; public DateTime babyData_createdate { get; set; } = DateTime.Now; public DateTime babyData_bindeddate { get; set; } = DateTime.Now; + public DateTime babyData_lastTestDate { get; set; } = DateTime.Now; } [Table("lineUser")] diff --git a/BackEnd/Login.aspx b/BackEnd/Login.aspx index 84961c5..1b79bdd 100644 --- a/BackEnd/Login.aspx +++ b/BackEnd/Login.aspx @@ -80,7 +80,7 @@ - + diff --git a/BackEnd/Main.Master b/BackEnd/Main.Master index 0946c55..fc11cdc 100644 --- a/BackEnd/Main.Master +++ b/BackEnd/Main.Master @@ -23,6 +23,11 @@ + + + + + - + + <%-- + --%> + + + + + + + + + + + + + + + + + + diff --git a/BackEnd/api/exportExcel.ashx b/BackEnd/api/exportExcel.ashx new file mode 100644 index 0000000..8863e88 --- /dev/null +++ b/BackEnd/api/exportExcel.ashx @@ -0,0 +1 @@ +<%@ WebHandler Language="C#" CodeBehind="exportExcel.ashx.cs" Class="abbott_2024_event.BackEnd.api.exportExcel" %> diff --git a/BackEnd/api/exportExcel.ashx.cs b/BackEnd/api/exportExcel.ashx.cs new file mode 100644 index 0000000..1716467 --- /dev/null +++ b/BackEnd/api/exportExcel.ashx.cs @@ -0,0 +1,163 @@ +using System; +using System.Web; +using NPOI; +//using NPOI.SS.UserModel; +using NPOI.HPSF; +using NPOI.HSSF; +using NPOI.HSSF.UserModel; +using NPOI.POIFS; +using NPOI.Util; +using System.IO; +using System.Runtime.Serialization.Json; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Web.SessionState; +using System.Collections.Generic; +using System.Data; +using System.Text; +using System.Data.SqlClient; +using System.Runtime.Remoting; +using Dapper; +using System.Linq; + +namespace abbott_2024_event.BackEnd.api +{ + /// + /// exportExcel 的摘要描述 + /// + public class exportExcel : IHttpHandler + { + SqlConnection conn = new SqlConnection(globalClass.appsettings("DBConnectionString")); + public authToken authToken; + public void ProcessRequest(HttpContext context) + { + authToken objAuth = new authToken(); + + if (!objAuth.user_isLogin) + { + context.Response.Write("尚未登入,請登入後使用"); + return; + } + + string start = (context.Request["start"] == null) ? "" : context.Request["start"].ToString(); + string end = (context.Request["end"] == null) ? "" : context.Request["end"].ToString(); + string gender = (context.Request["gender"] == null) ? "" : context.Request["gender"].ToString(); + string min_age = (context.Request["min_age"] == null) ? "" : context.Request["min_age"].ToString(); + string max_age = (context.Request["max_age"] == null) ? "" : context.Request["max_age"].ToString(); + + DateTime dateStart; + DateTime dateEnd; + + try + { + dateStart = DateTime.Parse(start); + dateEnd = DateTime.Parse(end + " 23:59:59"); + } + catch + { + context.Response.Write("測驗起訖日錯誤"); + return; + } + + if (gender != "%" && gender != "M" && gender != "F") + { + + context.Response.Write("性別代碼錯誤!"); + return; + } + + string filiterString = ""; + + filiterString += " Where babyData_bindedLine = 'Y' and babyRec_newestRec = 'Y' and babyRec_recdate >= '" + dateStart.ToString("yyyy/MM/dd") + "' and babyRec_recdate <= '" + dateEnd.ToString("yyyy/MM/dd HH:mm:ss") + "' "; + + if (gender != "%") + { + filiterString += " and babyData_sexual = '" + gender + "' "; + } + + filiterString += " and babyRec_months >= " + (int.Parse(min_age) * 12).ToString() + " and babyRec_months <= " + (int.Parse(max_age) * 12).ToString(); + + List babyDataRecViews = conn.Query("select * from babyDataRecView " + filiterString + " ").ToList(); + + HSSFWorkbook workbook = new HSSFWorkbook(); + MemoryStream ms = new MemoryStream(); + HSSFSheet sheet = (HSSFSheet)workbook.CreateSheet(); + HSSFRow headerRow = (HSSFRow)sheet.CreateRow(0); + + headerRow.CreateCell(0).SetCellValue("Line Uid"); + headerRow.CreateCell(1).SetCellValue("Line 名稱"); + headerRow.CreateCell(2).SetCellValue("寶寶姓名"); + headerRow.CreateCell(3).SetCellValue("寶寶性別"); + headerRow.CreateCell(4).SetCellValue("生日"); + headerRow.CreateCell(5).SetCellValue("測驗日期"); + headerRow.CreateCell(6).SetCellValue("測驗時年齡"); + headerRow.CreateCell(7).SetCellValue("寶寶身高"); + headerRow.CreateCell(8).SetCellValue("寶寶成長百分比"); + + int pageNum = 1; + + foreach (babyDataRecView view in babyDataRecViews) + { + string baby_gender = ""; + + if (view.babyData_sexual == "M") + { + baby_gender = "男"; + } + else { + baby_gender = "女"; + } + + string baby_inpercent = ""; + + if (view.babyRec_inpercent > 97) + { + baby_inpercent = "大於 97%"; + } + else { + baby_inpercent = view.babyRec_inpercent.ToString() + "%"; + + } + + + HSSFRow excelRow = (HSSFRow)sheet.CreateRow(pageNum); + excelRow.CreateCell(0).SetCellValue(view.line_uid); + excelRow.CreateCell(1).SetCellValue(view.line_displayName); + excelRow.CreateCell(2).SetCellValue(view.babyData_name); + excelRow.CreateCell(3).SetCellValue(baby_gender); + excelRow.CreateCell(4).SetCellValue(view.babyData_birthday.ToString("yyyy/MM/dd")); + excelRow.CreateCell(5).SetCellValue(view.babyRec_recdate.ToString("yyyy/MM/dd")); + excelRow.CreateCell(6).SetCellValue(view.babyRec_yearMonthStr); + excelRow.CreateCell(7).SetCellValue(view.babyRec_height); + excelRow.CreateCell(8).SetCellValue(baby_inpercent); + + pageNum++; + } + + for (int j = 0; j <= 8; j++) + { + sheet.AutoSizeColumn(j); + } + + + + workbook.Write(ms); + ms.Flush(); + + string fileName = HttpUtility.UrlEncode("測驗者寶寶成長資料_" + DateTime.Now.ToString("yyyy-MM-dd") + ".xls", Encoding.UTF8); + context.Response.ContentType = "application/vnd.ms-excel;charset=utf-8"; + context.Response.AddHeader("Content-Disposition", String.Format("attachment;filename=" + fileName + ";filename*=utf-8''" + fileName)); + //context.Response.ContentType = "application/vnd.ms-excel;charset=utf-8"; + context.Response.BinaryWrite(ms.ToArray()); + + } + + public bool IsReusable + { + get + { + return false; + } + } + } +} \ No newline at end of file diff --git a/BackEnd/api/userList.ashx b/BackEnd/api/userList.ashx new file mode 100644 index 0000000..aa52d18 --- /dev/null +++ b/BackEnd/api/userList.ashx @@ -0,0 +1 @@ +<%@ WebHandler Language="C#" CodeBehind="userList.ashx.cs" Class="abbott_2024_event.BackEnd.api.userList" %> diff --git a/BackEnd/api/userList.ashx.cs b/BackEnd/api/userList.ashx.cs new file mode 100644 index 0000000..dde4b68 --- /dev/null +++ b/BackEnd/api/userList.ashx.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Runtime.Serialization.Json; +using System.Web.SessionState; +using Dapper; +using Dapper.Contrib.Extensions; +using System.Data.SqlClient; +using System.IO.Compression; + +namespace abbott_2024_event.BackEnd.api +{ + /// + /// userList 的摘要描述 + /// + public class userList : IHttpHandler + { + SqlConnection conn = new SqlConnection(globalClass.appsettings("DBConnectionString")); + public authToken authToken; + public void ProcessRequest(HttpContext context) + { + result objRet = new result(); + DataContractJsonSerializer json = new DataContractJsonSerializer(objRet.GetType()); + context.Response.ContentType = "application/json;charset=utf-8"; + context.Response.AddHeader("Access-Control-Allow-Origin", "*"); + + string acceptEncoding = context.Request.Headers["Accept-Encoding"].ToString().ToUpperInvariant(); + if (!String.IsNullOrEmpty(acceptEncoding)) + { + if (acceptEncoding.Contains("GZIP")) + { + //输出流头部GZIP压缩 + context.Response.AppendHeader("Content-encoding", "gzip"); + context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); + } + else if (acceptEncoding.Contains("DEFLATE")) + { + //输出流头部DEFLATE压缩 + context.Response.AppendHeader("Content-encoding", "deflate"); + context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress); + } + } + + authToken objAuth = new authToken(); + + if (!objAuth.user_isLogin) + { + objRet.ret = "no"; + objRet.err_code = "0001"; + objRet.message = "尚未登入,請登入後使用"; + json.WriteObject(context.Response.OutputStream, objRet); + return; + } + + string start = (context.Request["start"] == null) ? "" : context.Request["start"].ToString(); + string end = (context.Request["end"] == null) ? "" : context.Request["end"].ToString(); + string gender = (context.Request["gender"] == null) ? "" : context.Request["gender"].ToString(); + string min_age = (context.Request["min_age"] == null) ? "" : context.Request["min_age"].ToString(); + string max_age = (context.Request["max_age"] == null) ? "" : context.Request["max_age"].ToString(); + + DateTime dateStart; + DateTime dateEnd; + + try { + dateStart = DateTime.Parse(start); + dateEnd = DateTime.Parse(end + " 23:59:59"); + } + catch { + objRet.ret = "no"; + objRet.err_code = "0008"; + objRet.message = "測驗記錄起訖日期有誤!"; + json.WriteObject(context.Response.OutputStream, objRet); + return; + } + + if (gender != "%" && gender != "M" && gender != "F") { + objRet.ret = "no"; + objRet.err_code = "0009"; + objRet.message = "性別代碼錯誤!"; + json.WriteObject(context.Response.OutputStream, objRet); + return; + } + + string filiterString = ""; + + filiterString += " Where babyData_bindedLine = 'Y' and babyRec_newestRec = 'Y' and babyRec_recdate >= '" + dateStart.ToString("yyyy/MM/dd") + "' and babyRec_recdate <= '" + dateEnd.ToString("yyyy/MM/dd HH:mm:ss") + "' "; + + if (gender != "%") { + filiterString += " and babyData_sexual = '" + gender + "' "; + } + + filiterString += " and babyRec_months >= " + (int.Parse(min_age) * 12).ToString() + " and babyRec_months <= " + (int.Parse(max_age) * 12).ToString(); + + List babyDataRecViews = conn.Query("select distinct line_uid, line_displayname from babyDataRecView " + filiterString + " ").ToList(); + + foreach (babyDataRecView view in babyDataRecViews) { + userData userData = new userData(); + userData.line_uid = view.line_uid; + userData.line_displayName = view.line_displayName; + + List subViews = conn.Query("select * from babyDataRecView " + filiterString + " and line_uid = @line_uid ", new { line_uid = view.line_uid }).ToList(); + + foreach (babyDataRecView subView in subViews) { + babyData babyData = new babyData(); + babyData.baby_name = subView.babyData_name; + babyData.baby_gender = subView.babyData_sexual; + babyData.baby_birthday = subView.babyData_birthday.ToString("yyyy/MM/dd"); + babyData.baby_age = subView.babyRec_yearMonthStr; + babyData.baby_months = subView.babyRec_months.ToString(); + babyData.baby_height = subView.babyRec_height.ToString(); + babyData.baby_testdate = subView.babyRec_recdate.ToString("yyyy/MM/dd"); + babyData.baby_percent = subView.babyRec_inpercent; + + userData.testdate = subView.babyRec_recdate.ToString("yyyy/MM/dd"); + + userData.babyDatas.Add(babyData); + + } + + objRet.datas.Add(userData); + + + } + + objRet.ret = "yes"; + + json.WriteObject(context.Response.OutputStream, objRet); + return; + + } + public class result + { + public string ret = "no"; + public string err_code = "0000"; + public string message = ""; + public List datas = new List(); + } + + public class userData + { + public string line_uid { get; set; } = ""; + public string line_displayName { get; set; } = ""; + public string testdate { get; set; } = ""; + + public List babyDatas = new List(); + } + + public class babyData { + public string baby_name { get; set; } = ""; + public string baby_gender { get; set; } = ""; + public string baby_birthday { get; set; } = ""; + public string baby_age { get; set; } = ""; + public string baby_months { get; set; } = ""; + public string baby_testdate { get; set; } = ""; + + public string baby_height { get; set; } = ""; + public double baby_percent { get; set; } = 0; + } + + public bool IsReusable + { + get + { + return false; + } + } + } +} \ No newline at end of file diff --git a/BackEnd/assets/javascript/custom/Login.js b/BackEnd/assets/javascript/custom/Login.js index 49f5f44..86eea48 100644 --- a/BackEnd/assets/javascript/custom/Login.js +++ b/BackEnd/assets/javascript/custom/Login.js @@ -42,7 +42,7 @@ $(document).ready(function () { data: formData, success: function (data, textStatus, jqXHR) { if (data.ret == "yes") { - location.href = "Index.aspx"; + location.href = "userList.aspx"; } else { alert(data.message); } diff --git a/BackEnd/assets/javascript/custom/userList.js b/BackEnd/assets/javascript/custom/userList.js new file mode 100644 index 0000000..0c746ea --- /dev/null +++ b/BackEnd/assets/javascript/custom/userList.js @@ -0,0 +1,238 @@ + +var oTable; +var oPos; + +$(document).ready(function () { + var actualDate = new Date(); // convert to actual date + var prevDate = new Date(actualDate.getFullYear(), actualDate.getMonth() - 6, actualDate.getDate()); + + var startTxt = prevDate.getFullYear().toString() + "/" + padding(prevDate.getMonth() + 1, 2) + "/01"; + var endTxt = actualDate.getFullYear().toString() + "/" + padding(actualDate.getMonth() + 1, 2) + "/" + padding(actualDate.getDate(), 2); + + $("#startDate").val(startTxt); + $("#endDate").val(endTxt); + $(".input-daterange").datepicker({ + format: "yyyy/mm/dd", + minViewMode: 0, + maxViewMode: 2, + orientation: "bottom auto", + language: "zh-TW", + autoclose: true + }); + + var start = $("#startDate").val(); + var end = $("#endDate").val(); + var gender = $("#gender_select").val(); + var min_age = $("#age_start").val(); + var max_age = $("#age_end").val(); + + $('#export_btn').click(function () { + var start = $("#startDate").val(); + var end = $("#endDate").val(); + var gender = $("#gender_select").val(); + var min_age = $("#age_start").val(); + var max_age = $("#age_end").val(); + + var url = "api/exportExcel.ashx?start=" + start + "&end=" + end + "&gender=" + gender + "&min_age=" + min_age + "&max_age=" + max_age; + window.open(url); + }); + + //$.ajax({ + // url: "api/userList.ashx", + // type: "POST", + // data: formData, + // success: function (data, textStatus, jqXHR) { + // if (data.ret == "yes") { + // location.href = "userList.aspx"; + // } else { + // alert(data.message); + // } + // }, + // error: function (jqXHR, textStatus, errorThrown) { + // alert('网絡或伺服器发生错误,请稍后重试!'); + // } + //}); + + + loadDataTable(); + + + + +}); + +function loadDataTable() { + var dataTables = { + init: function init() { + + this.bindUIActions(); + }, + bindUIActions: function bindUIActions() { + + // event handlers + this.table = this.handleDataTables(); + + // add buttons + //this.table.buttons().container().appendTo('#dt-buttons').unwrap(); + }, + handleDataTables: function handleDataTables() { + //$('#myTable').append(""); + return $('#myTable').DataTable({ + dom: '<\'text-muted\'Bif>\n <\'table-responsive\'trl>\n <\'mt-4\'p>', + lengthChange: true, + lengthMenu: [[25, 50, 100, -1], [25, 50, 100, "All"]], + pageLength: 50, + buttons: [ + //{ + // text: 'Excel', + // action: function (e, dt, node, config) { + + // var start = $("#startDate").val(); + // var end = $("#endDate").val(); + // var gender = $("#gender_select").val(); + // var min_age = $("#age_start").val(); + // var max_age = $("#age_end").val(); + + // var url = "api/exportExcel.ashx?start=" + start + "&end=" + end + "&gender=" + gender + "&min_age=" + min_age + "&max_age=" + max_age; + // window.open(url); + + // } + //} + ], + language: { + paginate: { + previous: '', + next: '' + }, + buttons: { + copyTitle: 'Data copied', + copyKeys: 'Use your keyboard or menu to select the copy command' + } + }, + autoWidth: false, + ajax: { + url: 'Api/userList.ashx', + type: 'POST', + data: function (d) { + Object.assign(d, { + start: $("#startDate").val(), + end: $("#endDate").val(), + gender: $("#gender_select").val(), + min_age: $("#age_start").val(), + max_age: $("#age_end").val() + }); + + return d; + }, + dataSrc: 'datas' + }, + rowId: 'line_uid', + deferRender: true, + initComplete: function () { + //mainItemTable = $('#dt-responsive').dataTable(); + $('#myTable').on('click', 'a', function () { + buttonClick(this); + }); + + $('#myTable').on('click', 'button', function () { + buttonClick(this); + }); + + + }, + order: [[2, 'desc']], + info: true, + search: "搜尋:", + searching: true, + columns: [ + { data: 'line_displayName', className: 'align-middle text-left', orderable: true, searchable: true }, + { data: 'line_uid', className: 'align-middle text-left', orderable: false, searchable: true }, + { data: 'testdate', className: 'align-top text-center', orderable: false, searchable: false, visible: false }, + { data: 'line_uid', className: 'align-middle text-left', orderable: false, searchable: false }, + { data: 'line_uid', className: 'align-middle text-center', orderable: false, searchable: false } + ], + columnDefs: [ + { + targets: 3, + className: 'align-middle text-left', + orderable: false, + searchable: true, + render: function render(data, type, row, meta) { + var gender = ''; + var inpercent = ''; + + + + + var htmlString = ''; + + $.each(row.babyDatas, function (i, item) { + if (item.baby_gender == 'M') { + gender = '男'; + } else { + gender = '女'; + } + + if (item.baby_percent > 97) { + inpercent = '> 97%'; + } else { + inpercent = item.baby_percent + '%'; + } + + htmlString += ""; + htmlString += " " + item.baby_name + "(" + gender + ")"; + htmlString += " 生日:" + item.baby_birthday + ""; + htmlString += " 測驗日期:" + item.baby_testdate + ""; + htmlString += " 年齡:" + item.baby_age + ""; + htmlString += " 身高:" + item.baby_height + " cm "; + htmlString += " 成長百分比:" + inpercent + ""; + htmlString += ""; + + }); + + htmlString = "" + htmlString + "
"; + + return htmlString; + + //return '' + row.company_name + ''; + + } + }, + { + targets: 4, + orderable: false, + searchable: false, + render: function render(data, type, row, meta) { + var ret = ''; + + ret += ''; + return ret; + } + } + + ] + }); + }, + handleSearchRecords: function handleSearchRecords() { + var self = this; + + $('#table-search, #filterBy').on('keyup change focus', function (e) { + var filterBy = $('#filterBy').val(); + var hasFilter = filterBy !== ''; + var value = $('#table-search').val(); + + self.table.search('').columns().search('').draw(); + + if (hasFilter) { + self.table.columns(filterBy).search(value).draw(); + } else { + self.table.search(value).draw(); + } + + }); + } + } + + dataTables.init(); +} + diff --git a/BackEnd/assets/javascript/pages/dataTables.fixedHeader.min.js b/BackEnd/assets/javascript/pages/dataTables.fixedHeader.min.js new file mode 100644 index 0000000..6ab2ab0 --- /dev/null +++ b/BackEnd/assets/javascript/pages/dataTables.fixedHeader.min.js @@ -0,0 +1,18 @@ +/*! + FixedHeader 3.1.5 + ©2009-2018 SpryMedia Ltd - datatables.net/license +*/ +(function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(g){return d(g,window,document)}):"object"===typeof exports?module.exports=function(g,i){g||(g=window);if(!i||!i.fn.dataTable)i=require("datatables.net")(g,i).$;return d(i,g,g.document)}:d(jQuery,window,document)})(function(d,g,i,k){var j=d.fn.dataTable,l=0,h=function(a,b){if(!(this instanceof h))throw"FixedHeader must be initialised with the 'new' keyword.";!0===b&&(b={});a=new j.Api(a);this.c=d.extend(!0, +{},h.defaults,b);this.s={dt:a,position:{theadTop:0,tbodyTop:0,tfootTop:0,tfootBottom:0,width:0,left:0,tfootHeight:0,theadHeight:0,windowHeight:d(g).height(),visible:!0},headerMode:null,footerMode:null,autoWidth:a.settings()[0].oFeatures.bAutoWidth,namespace:".dtfc"+l++,scrollLeft:{header:-1,footer:-1},enable:!0};this.dom={floatingHeader:null,thead:d(a.table().header()),tbody:d(a.table().body()),tfoot:d(a.table().footer()),header:{host:null,floating:null,placeholder:null},footer:{host:null,floating:null, +placeholder:null}};this.dom.header.host=this.dom.thead.parent();this.dom.footer.host=this.dom.tfoot.parent();var e=a.settings()[0];if(e._fixedHeader)throw"FixedHeader already initialised on table "+e.nTable.id;e._fixedHeader=this;this._constructor()};d.extend(h.prototype,{enable:function(a){this.s.enable=a;this.c.header&&this._modeChange("in-place","header",!0);this.c.footer&&this.dom.tfoot.length&&this._modeChange("in-place","footer",!0);this.update()},headerOffset:function(a){a!==k&&(this.c.headerOffset= +a,this.update());return this.c.headerOffset},footerOffset:function(a){a!==k&&(this.c.footerOffset=a,this.update());return this.c.footerOffset},update:function(){this._positions();this._scroll(!0)},_constructor:function(){var a=this,b=this.s.dt;d(g).on("scroll"+this.s.namespace,function(){a._scroll()}).on("resize"+this.s.namespace,j.util.throttle(function(){a.s.position.windowHeight=d(g).height();a.update()},50));var e=d(".fh-fixedHeader");!this.c.headerOffset&&e.length&&(this.c.headerOffset=e.outerHeight()); +e=d(".fh-fixedFooter");!this.c.footerOffset&&e.length&&(this.c.footerOffset=e.outerHeight());b.on("column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc",function(){a.update()});b.on("destroy.dtfc",function(){a.c.header&&a._modeChange("in-place","header",true);a.c.footer&&a.dom.tfoot.length&&a._modeChange("in-place","footer",true);b.off(".dtfc");d(g).off(a.s.namespace)});this._positions();this._scroll()},_clone:function(a,b){var e=this.s.dt, +c=this.dom[a],f="header"===a?this.dom.thead:this.dom.tfoot;!b&&c.floating?c.floating.removeClass("fixedHeader-floating fixedHeader-locked"):(c.floating&&(c.placeholder.remove(),this._unsize(a),c.floating.children().detach(),c.floating.remove()),c.floating=d(e.table().node().cloneNode(!1)).css("table-layout","fixed").attr("aria-hidden","true").removeAttr("id").append(f).appendTo("body"),c.placeholder=f.clone(!1),c.placeholder.find("*[id]").removeAttr("id"),c.host.prepend(c.placeholder),this._matchWidths(c.placeholder, +c.floating))},_matchWidths:function(a,b){var e=function(b){return d(b,a).map(function(){return d(this).width()}).toArray()},c=function(a,c){d(a,b).each(function(a){d(this).css({width:c[a],minWidth:c[a]})})},f=e("th"),e=e("td");c("th",f);c("td",e)},_unsize:function(a){var b=this.dom[a].floating;b&&("footer"===a||"header"===a&&!this.s.autoWidth)?d("th, td",b).css({width:"",minWidth:""}):b&&"header"===a&&d("th, td",b).css("min-width","")},_horizontal:function(a,b){var e=this.dom[a],c=this.s.position, +d=this.s.scrollLeft;e.floating&&d[a]!==b&&(e.floating.css("left",c.left-b),d[a]=b)},_modeChange:function(a,b,e){var c=this.dom[b],f=this.s.position,g=this.dom["footer"===b?"tfoot":"thead"],h=d.contains(g[0],i.activeElement)?i.activeElement:null;h&&h.blur();if("in-place"===a){if(c.placeholder&&(c.placeholder.remove(),c.placeholder=null),this._unsize(b),"header"===b?c.host.prepend(g):c.host.append(g),c.floating)c.floating.remove(),c.floating=null}else"in"===a?(this._clone(b,e),c.floating.addClass("fixedHeader-floating").css("header"=== +b?"top":"bottom",this.c[b+"Offset"]).css("left",f.left+"px").css("width",f.width+"px"),"footer"===b&&c.floating.css("top","")):"below"===a?(this._clone(b,e),c.floating.addClass("fixedHeader-locked").css("top",f.tfootTop-f.theadHeight).css("left",f.left+"px").css("width",f.width+"px")):"above"===a&&(this._clone(b,e),c.floating.addClass("fixedHeader-locked").css("top",f.tbodyTop).css("left",f.left+"px").css("width",f.width+"px"));h&&h!==i.activeElement&&setTimeout(function(){h.focus()},10);this.s.scrollLeft.header= +-1;this.s.scrollLeft.footer=-1;this.s[b+"Mode"]=a},_positions:function(){var a=this.s.dt.table(),b=this.s.position,e=this.dom,a=d(a.node()),c=a.children("thead"),f=a.children("tfoot"),e=e.tbody;b.visible=a.is(":visible");b.width=a.outerWidth();b.left=a.offset().left;b.theadTop=c.offset().top;b.tbodyTop=e.offset().top;b.theadHeight=b.tbodyTop-b.theadTop;f.length?(b.tfootTop=f.offset().top,b.tfootBottom=b.tfootTop+f.outerHeight(),b.tfootHeight=b.tfootBottom-b.tfootTop):(b.tfootTop=b.tbodyTop+e.outerHeight(), +b.tfootBottom=b.tfootTop,b.tfootHeight=b.tfootTop)},_scroll:function(a){var b=d(i).scrollTop(),e=d(i).scrollLeft(),c=this.s.position,f;if(this.s.enable&&(this.c.header&&(f=!c.visible||b<=c.theadTop-this.c.headerOffset?"in-place":b<=c.tfootTop-c.theadHeight-this.c.headerOffset?"in":"below",(a||f!==this.s.headerMode)&&this._modeChange(f,"header",a),this._horizontal("header",e)),this.c.footer&&this.dom.tfoot.length))b=!c.visible||b+c.windowHeight>=c.tfootBottom+this.c.footerOffset?"in-place":c.windowHeight+ +b>c.tbodyTop+c.tfootHeight+this.c.footerOffset?"in":"above",(a||b!==this.s.footerMode)&&this._modeChange(b,"footer",a),this._horizontal("footer",e)}});h.version="3.1.5";h.defaults={header:!0,footer:!1,headerOffset:0,footerOffset:0};d.fn.dataTable.FixedHeader=h;d.fn.DataTable.FixedHeader=h;d(i).on("init.dt.dtfh",function(a,b){if("dt"===a.namespace){var e=b.oInit.fixedHeader,c=j.defaults.fixedHeader;if((e||c)&&!b._fixedHeader)c=d.extend({},c,e),!1!==e&&new h(b,c)}});j.Api.register("fixedHeader()",function(){}); +j.Api.register("fixedHeader.adjust()",function(){return this.iterator("table",function(a){(a=a._fixedHeader)&&a.update()})});j.Api.register("fixedHeader.enable()",function(a){return this.iterator("table",function(b){b=b._fixedHeader;a=a!==k?a:!0;b&&a!==b.s.enable&&b.enable(a)})});j.Api.register("fixedHeader.disable()",function(){return this.iterator("table",function(a){(a=a._fixedHeader)&&a.s.enable&&a.enable(!1)})});d.each(["header","footer"],function(a,b){j.Api.register("fixedHeader."+b+"Offset()", +function(a){var c=this.context;return a===k?c.length&&c[0]._fixedHeader?c[0]._fixedHeader[b+"Offset"]():k:this.iterator("table",function(c){if(c=c._fixedHeader)c[b+"Offset"](a)})})});return h}); diff --git a/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.css b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.css new file mode 100644 index 0000000..06246d4 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.css @@ -0,0 +1,87 @@ +div.dt-autofill-handle { + position: absolute; + height: 8px; + width: 8px; + z-index: 102; + box-sizing: border-box; + border: 1px solid #0275d8; + background: #0275d8; +} + +div.dt-autofill-select { + position: absolute; + z-index: 1001; + background-color: #0275d8; + background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px); +} +div.dt-autofill-select.top, div.dt-autofill-select.bottom { + height: 3px; + margin-top: -1px; +} +div.dt-autofill-select.left, div.dt-autofill-select.right { + width: 3px; + margin-left: -1px; +} + +div.dt-autofill-list { + position: fixed; + top: 50%; + left: 50%; + width: 500px; + margin-left: -250px; + background-color: white; + border-radius: 6px; + box-shadow: 0 0 5px #555; + border: 2px solid #444; + z-index: 11; + box-sizing: border-box; + padding: 1.5em 2em; +} +div.dt-autofill-list ul { + display: table; + margin: 0; + padding: 0; + list-style: none; + width: 100%; +} +div.dt-autofill-list ul li { + display: table-row; +} +div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button { + border-bottom: none; +} +div.dt-autofill-list ul li:hover { + background-color: #f6f6f6; +} +div.dt-autofill-list div.dt-autofill-question { + display: table-cell; + padding: 0.5em 0; + border-bottom: 1px solid #ccc; +} +div.dt-autofill-list div.dt-autofill-question input[type=number] { + padding: 6px; + width: 30px; + margin: -2px 0; +} +div.dt-autofill-list div.dt-autofill-button { + display: table-cell; + padding: 0.5em 0; + border-bottom: 1px solid #ccc; +} + +div.dt-autofill-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + z-index: 10; +} + +div.dt-autofill-list div.dt-autofill-question input[type=number] { + padding: 6px; + width: 60px; + margin: -2px 0; +} diff --git a/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.js b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.js new file mode 100644 index 0000000..40037e4 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.js @@ -0,0 +1,43 @@ +/*! Bootstrap integration for DataTables' AutoFill + * ©2015 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs4', 'datatables.net-autofill'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-bs4')(root, $).$; + } + + if ( ! $.fn.dataTable.AutoFill ) { + require('datatables.net-autofill')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +DataTable.AutoFill.classes.btn = 'btn btn-primary'; + + +return DataTable; +})); \ No newline at end of file diff --git a/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.min.css b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.min.css new file mode 100644 index 0000000..603c33e --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.min.css @@ -0,0 +1 @@ +div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #0275d8;background:#0275d8}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#0275d8;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:60px;margin:-2px 0} diff --git a/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.min.js b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.min.js new file mode 100644 index 0000000..87ea58c --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/autofill/autoFill.bootstrap4.min.js @@ -0,0 +1,5 @@ +/*! + Bootstrap integration for DataTables' AutoFill + ©2015 SpryMedia Ltd - datatables.net/license +*/ +(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs4","datatables.net-autofill"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);if(!c||!c.fn.dataTable)c=require("datatables.net-bs4")(b,c).$;c.fn.dataTable.AutoFill||require("datatables.net-autofill")(b,c);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a){a=a.fn.dataTable;a.AutoFill.classes.btn="btn btn-primary";return a}); diff --git a/BackEnd/assets/vendor/datatables/extensions/autofill/dataTables.autoFill.js b/BackEnd/assets/vendor/datatables/extensions/autofill/dataTables.autoFill.js new file mode 100644 index 0000000..6031228 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/autofill/dataTables.autoFill.js @@ -0,0 +1,1199 @@ +/*! AutoFill 2.3.1 + * ©2008-2018 SpryMedia Ltd - datatables.net/license + */ + +/** + * @summary AutoFill + * @description Add Excel like click and drag auto-fill options to DataTables + * @version 2.3.1 + * @file dataTables.autoFill.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright 2010-2018 SpryMedia Ltd. + * + * This source file is free software, available under the following license: + * MIT license - http://datatables.net/license/mit + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + * + * For details please refer to: http://www.datatables.net + */ +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net')(root, $).$; + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +var _instance = 0; + +/** + * AutoFill provides Excel like auto-fill features for a DataTable + * + * @class AutoFill + * @constructor + * @param {object} oTD DataTables settings object + * @param {object} oConfig Configuration object for AutoFill + */ +var AutoFill = function( dt, opts ) +{ + if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) { + throw( "Warning: AutoFill requires DataTables 1.10.8 or greater"); + } + + // User and defaults configuration object + this.c = $.extend( true, {}, + DataTable.defaults.autoFill, + AutoFill.defaults, + opts + ); + + /** + * @namespace Settings object which contains customisable information for AutoFill instance + */ + this.s = { + /** @type {DataTable.Api} DataTables' API instance */ + dt: new DataTable.Api( dt ), + + /** @type {String} Unique namespace for events attached to the document */ + namespace: '.autoFill'+(_instance++), + + /** @type {Object} Cached dimension information for use in the mouse move event handler */ + scroll: {}, + + /** @type {integer} Interval object used for smooth scrolling */ + scrollInterval: null, + + handle: { + height: 0, + width: 0 + }, + + /** + * Enabled setting + * @type {Boolean} + */ + enabled: false + }; + + + /** + * @namespace Common and useful DOM elements for the class instance + */ + this.dom = { + /** @type {jQuery} AutoFill handle */ + handle: $('
'), + + /** + * @type {Object} Selected cells outline - Need to use 4 elements, + * otherwise the mouse over if you back into the selected rectangle + * will be over that element, rather than the cells! + */ + select: { + top: $('
'), + right: $('
'), + bottom: $('
'), + left: $('
') + }, + + /** @type {jQuery} Fill type chooser background */ + background: $('
'), + + /** @type {jQuery} Fill type chooser */ + list: $('
'+this.s.dt.i18n('autoFill.info', '')+'
    '), + + /** @type {jQuery} DataTables scrolling container */ + dtScroll: null, + + /** @type {jQuery} Offset parent element */ + offsetParent: null + }; + + + /* Constructor logic */ + this._constructor(); +}; + + + +$.extend( AutoFill.prototype, { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public methods (exposed via the DataTables API below) + */ + enabled: function () + { + return this.s.enabled; + }, + + + enable: function ( flag ) + { + var that = this; + + if ( flag === false ) { + return this.disable(); + } + + this.s.enabled = true; + + this._focusListener(); + + this.dom.handle.on( 'mousedown', function (e) { + that._mousedown( e ); + return false; + } ); + + return this; + }, + + disable: function () + { + this.s.enabled = false; + + this._focusListenerRemove(); + + return this; + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Constructor + */ + + /** + * Initialise the RowReorder instance + * + * @private + */ + _constructor: function () + { + var that = this; + var dt = this.s.dt; + var dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container()); + + // Make the instance accessible to the API + dt.settings()[0].autoFill = this; + + if ( dtScroll.length ) { + this.dom.dtScroll = dtScroll; + + // Need to scroll container to be the offset parent + if ( dtScroll.css('position') === 'static' ) { + dtScroll.css( 'position', 'relative' ); + } + } + + if ( this.c.enable !== false ) { + this.enable(); + } + + dt.on( 'destroy.autoFill', function () { + that._focusListenerRemove(); + } ); + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Private methods + */ + + /** + * Display the AutoFill drag handle by appending it to a table cell. This + * is the opposite of the _detach method. + * + * @param {node} node TD/TH cell to insert the handle into + * @private + */ + _attach: function ( node ) + { + var dt = this.s.dt; + var idx = dt.cell( node ).index(); + var handle = this.dom.handle; + var handleDim = this.s.handle; + + if ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) { + this._detach(); + return; + } + + if ( ! this.dom.offsetParent ) { + // We attach to the table's offset parent + this.dom.offsetParent = $( dt.table().node() ).offsetParent(); + } + + if ( ! handleDim.height || ! handleDim.width ) { + // Append to document so we can get its size. Not expecting it to + // change during the life time of the page + handle.appendTo( 'body' ); + handleDim.height = handle.outerHeight(); + handleDim.width = handle.outerWidth(); + } + + // Might need to go through multiple offset parents + var offset = this._getPosition( node, this.dom.offsetParent ); + + this.dom.attachedTo = node; + handle + .css( { + top: offset.top + node.offsetHeight - handleDim.height, + left: offset.left + node.offsetWidth - handleDim.width + } ) + .appendTo( this.dom.offsetParent ); + }, + + + /** + * Determine can the fill type should be. This can be automatic, or ask the + * end user. + * + * @param {array} cells Information about the selected cells from the key + * up function + * @private + */ + _actionSelector: function ( cells ) + { + var that = this; + var dt = this.s.dt; + var actions = AutoFill.actions; + var available = []; + + // "Ask" each plug-in if it wants to handle this data + $.each( actions, function ( key, action ) { + if ( action.available( dt, cells ) ) { + available.push( key ); + } + } ); + + if ( available.length === 1 && this.c.alwaysAsk === false ) { + // Only one action available - enact it immediately + var result = actions[ available[0] ].execute( dt, cells ); + this._update( result, cells ); + } + else { + // Multiple actions available - ask the end user what they want to do + var list = this.dom.list.children('ul').empty(); + + // Add a cancel option + available.push( 'cancel' ); + + $.each( available, function ( i, name ) { + list.append( $('
  • ') + .append( + '
    '+ + actions[ name ].option( dt, cells )+ + '
    ' + ) + .append( $('
    ' ) + .append( $('') + .on( 'click', function () { + var result = actions[ name ].execute( + dt, cells, $(this).closest('li') + ); + that._update( result, cells ); + + that.dom.background.remove(); + that.dom.list.remove(); + } ) + ) + ) + ); + } ); + + this.dom.background.appendTo( 'body' ); + this.dom.list.appendTo( 'body' ); + + this.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 ); + } + }, + + + /** + * Remove the AutoFill handle from the document + * + * @private + */ + _detach: function () + { + this.dom.attachedTo = null; + this.dom.handle.detach(); + }, + + + /** + * Draw the selection outline by calculating the range between the start + * and end cells, then placing the highlighting elements to draw a rectangle + * + * @param {node} target End cell + * @param {object} e Originating event + * @private + */ + _drawSelection: function ( target, e ) + { + // Calculate boundary for start cell to this one + var dt = this.s.dt; + var start = this.s.start; + var startCell = $(this.dom.start); + var end = { + row: this.c.vertical ? + dt.rows( { page: 'current' } ).nodes().indexOf( target.parentNode ) : + start.row, + column: this.c.horizontal ? + $(target).index() : + start.column + }; + var colIndx = dt.column.index( 'toData', end.column ); + var endCell = $( dt.cell( ':eq('+end.row+')', colIndx ).node() ); + + // Be sure that is a DataTables controlled cell + if ( ! dt.cell( endCell ).any() ) { + return; + } + + // if target is not in the columns available - do nothing + if ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 ) { + return; + } + + this.s.end = end; + + var top, bottom, left, right, height, width; + + top = start.row < end.row ? startCell : endCell; + bottom = start.row < end.row ? endCell : startCell; + left = start.column < end.column ? startCell : endCell; + right = start.column < end.column ? endCell : startCell; + + top = this._getPosition( top ).top; + left = this._getPosition( left ).left; + height = this._getPosition( bottom ).top + bottom.outerHeight() - top; + width = this._getPosition( right ).left + right.outerWidth() - left; + + var select = this.dom.select; + select.top.css( { + top: top, + left: left, + width: width + } ); + + select.left.css( { + top: top, + left: left, + height: height + } ); + + select.bottom.css( { + top: top + height, + left: left, + width: width + } ); + + select.right.css( { + top: top, + left: left + width, + height: height + } ); + }, + + + /** + * Use the Editor API to perform an update based on the new data for the + * cells + * + * @param {array} cells Information about the selected cells from the key + * up function + * @private + */ + _editor: function ( cells ) + { + var dt = this.s.dt; + var editor = this.c.editor; + + if ( ! editor ) { + return; + } + + // Build the object structure for Editor's multi-row editing + var idValues = {}; + var nodes = []; + var fields = editor.fields(); + + for ( var i=0, ien=cells.length ; i=end ; i-- ) { + out.push( i ); + } + } + + return out; + }, + + + /** + * Move the window and DataTables scrolling during a drag to scroll new + * content into view. This is done by proximity to the edge of the scrolling + * container of the mouse - for example near the top edge of the window + * should scroll up. This is a little complicated as there are two elements + * that can be scrolled - the window and the DataTables scrolling view port + * (if scrollX and / or scrollY is enabled). + * + * @param {object} e Mouse move event object + * @private + */ + _shiftScroll: function ( e ) + { + var that = this; + var dt = this.s.dt; + var scroll = this.s.scroll; + var runInterval = false; + var scrollSpeed = 5; + var buffer = 65; + var + windowY = e.pageY - document.body.scrollTop, + windowX = e.pageX - document.body.scrollLeft, + windowVert, windowHoriz, + dtVert, dtHoriz; + + // Window calculations - based on the mouse position in the window, + // regardless of scrolling + if ( windowY < buffer ) { + windowVert = scrollSpeed * -1; + } + else if ( windowY > scroll.windowHeight - buffer ) { + windowVert = scrollSpeed; + } + + if ( windowX < buffer ) { + windowHoriz = scrollSpeed * -1; + } + else if ( windowX > scroll.windowWidth - buffer ) { + windowHoriz = scrollSpeed; + } + + // DataTables scrolling calculations - based on the table's position in + // the document and the mouse position on the page + if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) { + dtVert = scrollSpeed * -1; + } + else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) { + dtVert = scrollSpeed; + } + + if ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) { + dtHoriz = scrollSpeed * -1; + } + else if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) { + dtHoriz = scrollSpeed; + } + + // This is where it gets interesting. We want to continue scrolling + // without requiring a mouse move, so we need an interval to be + // triggered. The interval should continue until it is no longer needed, + // but it must also use the latest scroll commands (for example consider + // that the mouse might move from scrolling up to scrolling left, all + // with the same interval running. We use the `scroll` object to "pass" + // this information to the interval. Can't use local variables as they + // wouldn't be the ones that are used by an already existing interval! + if ( windowVert || windowHoriz || dtVert || dtHoriz ) { + scroll.windowVert = windowVert; + scroll.windowHoriz = windowHoriz; + scroll.dtVert = dtVert; + scroll.dtHoriz = dtHoriz; + runInterval = true; + } + else if ( this.s.scrollInterval ) { + // Don't need to scroll - remove any existing timer + clearInterval( this.s.scrollInterval ); + this.s.scrollInterval = null; + } + + // If we need to run the interval to scroll and there is no existing + // interval (if there is an existing one, it will continue to run) + if ( ! this.s.scrollInterval && runInterval ) { + this.s.scrollInterval = setInterval( function () { + // Don't need to worry about setting scroll <0 or beyond the + // scroll bound as the browser will just reject that. + if ( scroll.windowVert ) { + document.body.scrollTop += scroll.windowVert; + } + if ( scroll.windowHoriz ) { + document.body.scrollLeft += scroll.windowHoriz; + } + + // DataTables scrolling + if ( scroll.dtVert || scroll.dtHoriz ) { + var scroller = that.dom.dtScroll[0]; + + if ( scroll.dtVert ) { + scroller.scrollTop += scroll.dtVert; + } + if ( scroll.dtHoriz ) { + scroller.scrollLeft += scroll.dtHoriz; + } + } + }, 20 ); + } + }, + + + /** + * Update the DataTable after the user has selected what they want to do + * + * @param {false|undefined} result Return from the `execute` method - can + * be false internally to do nothing. This is not documented for plug-ins + * and is used only by the cancel option. + * @param {array} cells Information about the selected cells from the key + * up function, argumented with the set values + * @private + */ + _update: function ( result, cells ) + { + // Do nothing on `false` return from an execute function + if ( result === false ) { + return; + } + + var dt = this.s.dt; + var cell; + + // Potentially allow modifications to the cells matrix + this._emitEvent( 'preAutoFill', [ dt, cells ] ); + + this._editor( cells ); + + // Automatic updates are not performed if `update` is null and the + // `editor` parameter is passed in - the reason being that Editor will + // update the data once submitted + var update = this.c.update !== null ? + this.c.update : + this.c.editor ? + false : + true; + + if ( update ) { + for ( var i=0, ien=cells.length ; i' + ); + }, + + execute: function ( dt, cells, node ) { + var value = cells[0][0].data * 1; + var increment = $('input', node).val() * 1; + + for ( var i=0, ien=cells.length ; i'+cells[0][0].label+'' ); + }, + + execute: function ( dt, cells, node ) { + var value = cells[0][0].data; + + for ( var i=0, ien=cells.length ; i 1 && cells[0].length > 1; + }, + + option: function ( dt, cells ) { + return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' ); + }, + + execute: function ( dt, cells, node ) { + for ( var i=0, ien=cells.length ; i 1 && cells[0].length > 1; + }, + + option: function ( dt, cells ) { + return dt.i18n('autoFill.fillVertical', 'Fill cells vertically' ); + }, + + execute: function ( dt, cells, node ) { + for ( var i=0, ien=cells.length ; i'),select:{top:f('
    '),right:f('
    '),bottom:f('
    '),left:f('
    ')},background:f('
    '),list:f('
    '+this.s.dt.i18n("autoFill.info", +"")+"
      "),dtScroll:null,offsetParent:null};this._constructor()};f.extend(h.prototype,{enabled:function(){return this.s.enabled},enable:function(b){var c=this;if(!1===b)return this.disable();this.s.enabled=!0;this._focusListener();this.dom.handle.on("mousedown",function(a){c._mousedown(a);return!1});return this},disable:function(){this.s.enabled=!1;this._focusListenerRemove();return this},_constructor:function(){var b=this,c=this.s.dt,a=f("div.dataTables_scrollBody",this.s.dt.table().container()); +c.settings()[0].autoFill=this;a.length&&(this.dom.dtScroll=a,"static"===a.css("position")&&a.css("position","relative"));!1!==this.c.enable&&this.enable();c.on("destroy.autoFill",function(){b._focusListenerRemove()})},_attach:function(b){var c=this.s.dt,a=c.cell(b).index(),d=this.dom.handle,e=this.s.handle;if(!a||-1===c.columns(this.c.columns).indexes().indexOf(a.column))this._detach();else{this.dom.offsetParent||(this.dom.offsetParent=f(c.table().node()).offsetParent());if(!e.height||!e.width)d.appendTo("body"), +e.height=d.outerHeight(),e.width=d.outerWidth();c=this._getPosition(b,this.dom.offsetParent);this.dom.attachedTo=b;d.css({top:c.top+b.offsetHeight-e.height,left:c.left+b.offsetWidth-e.width}).appendTo(this.dom.offsetParent)}},_actionSelector:function(b){var c=this,a=this.s.dt,d=h.actions,e=[];f.each(d,function(c,d){d.available(a,b)&&e.push(c)});if(1===e.length&&!1===this.c.alwaysAsk){var i=d[e[0]].execute(a,b);this._update(i,b)}else{var g=this.dom.list.children("ul").empty();e.push("cancel");f.each(e, +function(e,i){g.append(f("
    • ").append('
      '+d[i].option(a,b)+"
      ").append(f('
      ').append(f('").on("click",function(){var e=d[i].execute(a,b,f(this).closest("li"));c._update(e,b);c.dom.background.remove();c.dom.list.remove()}))))});this.dom.background.appendTo("body");this.dom.list.appendTo("body");this.dom.list.css("margin-top",-1*(this.dom.list.outerHeight()/ +2))}},_detach:function(){this.dom.attachedTo=null;this.dom.handle.detach()},_drawSelection:function(b){var c=this.s.dt,a=this.s.start,d=f(this.dom.start),e={row:this.c.vertical?c.rows({page:"current"}).nodes().indexOf(b.parentNode):a.row,column:this.c.horizontal?f(b).index():a.column},b=c.column.index("toData",e.column),i=f(c.cell(":eq("+e.row+")",b).node());if(c.cell(i).any()&&-1!==c.columns(this.c.columns).indexes().indexOf(b)){this.s.end=e;var g,c=a.row=c;d--)a.push(d);return a},_shiftScroll:function(b){var c=this,a=this.s.scroll,d=!1,e=b.pageY-k.body.scrollTop,f=b.pageX-k.body.scrollLeft,g,h,j,l;65>e?g=-5:e>a.windowHeight-65&&(g=5);65>f?h=-5:f>a.windowWidth-65&&(h=5);null!==a.dtTop&&b.pageYa.dtTop+a.dtHeight-65&&(j=5);null!==a.dtLeft&&b.pageXa.dtLeft+a.dtWidth-65&&(l=5);g||h||j||l?(a.windowVert=g,a.windowHoriz=h,a.dtVert=j,a.dtHoriz=l,d=!0):this.s.scrollInterval&& +(clearInterval(this.s.scrollInterval),this.s.scrollInterval=null);!this.s.scrollInterval&&d&&(this.s.scrollInterval=setInterval(function(){if(a.windowVert)k.body.scrollTop=k.body.scrollTop+a.windowVert;if(a.windowHoriz)k.body.scrollLeft=k.body.scrollLeft+a.windowHoriz;if(a.dtVert||a.dtHoriz){var b=c.dom.dtScroll[0];if(a.dtVert)b.scrollTop=b.scrollTop+a.dtVert;if(a.dtHoriz)b.scrollLeft=b.scrollLeft+a.dtHoriz}},20))},_update:function(b,c){if(!1!==b){var a=this.s.dt,d;this._emitEvent("preAutoFill",[a, +c]);this._editor(c);if(null!==this.c.update?this.c.update:!this.c.editor){for(var e=0,f=c.length;e')},execute:function(b,c,a){for(var b=1*c[0][0].data,a=1*f("input", +a).val(),d=0,e=c.length;d"+c[0][0].label+"")},execute:function(b,c){for(var a=c[0][0].data,d=0,e=c.length;d div { + padding: 1em; +} + +ul.dt-button-collection.dropdown-menu { + display: block; + z-index: 2002; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +ul.dt-button-collection.dropdown-menu.fixed { + position: fixed; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 0; +} +ul.dt-button-collection.dropdown-menu.fixed.two-column { + margin-left: -150px; +} +ul.dt-button-collection.dropdown-menu.fixed.three-column { + margin-left: -225px; +} +ul.dt-button-collection.dropdown-menu.fixed.four-column { + margin-left: -300px; +} +ul.dt-button-collection.dropdown-menu > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +ul.dt-button-collection.dropdown-menu.two-column { + width: 300px; + padding-bottom: 1px; + -webkit-column-count: 2; + -moz-column-count: 2; + -ms-column-count: 2; + -o-column-count: 2; + column-count: 2; +} +ul.dt-button-collection.dropdown-menu.three-column { + width: 450px; + padding-bottom: 1px; + -webkit-column-count: 3; + -moz-column-count: 3; + -ms-column-count: 3; + -o-column-count: 3; + column-count: 3; +} +ul.dt-button-collection.dropdown-menu.four-column { + width: 600px; + padding-bottom: 1px; + -webkit-column-count: 4; + -moz-column-count: 4; + -ms-column-count: 4; + -o-column-count: 4; + column-count: 4; +} +ul.dt-button-collection.dropdown-menu .dt-button { + border-radius: 0; +} + +ul.dt-button-collection { + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +ul.dt-button-collection.fixed { + position: fixed; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 0; +} +ul.dt-button-collection.fixed.two-column { + margin-left: -150px; +} +ul.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +ul.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +ul.dt-button-collection > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +ul.dt-button-collection.two-column { + width: 300px; + padding-bottom: 1px; + -webkit-column-count: 2; + -moz-column-count: 2; + -ms-column-count: 2; + -o-column-count: 2; + column-count: 2; +} +ul.dt-button-collection.three-column { + width: 450px; + padding-bottom: 1px; + -webkit-column-count: 3; + -moz-column-count: 3; + -ms-column-count: 3; + -o-column-count: 3; + column-count: 3; +} +ul.dt-button-collection.four-column { + width: 600px; + padding-bottom: 1px; + -webkit-column-count: 4; + -moz-column-count: 4; + -ms-column-count: 4; + -o-column-count: 4; + column-count: 4; +} +ul.dt-button-collection .dt-button { + border-radius: 0; +} +ul.dt-button-collection.fixed { + max-width: none; +} +ul.dt-button-collection.fixed:before, ul.dt-button-collection.fixed:after { + display: none; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: ' '; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} diff --git a/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.js b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.js new file mode 100644 index 0000000..4a3e489 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.js @@ -0,0 +1,62 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs4', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-bs4')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons btn-group' + }, + button: { + className: 'btn btn-secondary' + }, + collection: { + tag: 'div', + className: 'dt-button-collection dropdown-menu', + button: { + tag: 'a', + className: 'dt-button dropdown-item', + active: 'active', + disabled: 'disabled' + } + } + } +} ); + +DataTable.ext.buttons.collection.className += ' dropdown-toggle'; + +return DataTable.Buttons; +})); diff --git a/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.min.css b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.min.css new file mode 100644 index 0000000..dcf41c6 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}ul.dt-button-collection.dropdown-menu{display:block;z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}ul.dt-button-collection.dropdown-menu.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}ul.dt-button-collection.dropdown-menu.fixed.two-column{margin-left:-150px}ul.dt-button-collection.dropdown-menu.fixed.three-column{margin-left:-225px}ul.dt-button-collection.dropdown-menu.fixed.four-column{margin-left:-300px}ul.dt-button-collection.dropdown-menu>*{-webkit-column-break-inside:avoid;break-inside:avoid}ul.dt-button-collection.dropdown-menu.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}ul.dt-button-collection.dropdown-menu.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}ul.dt-button-collection.dropdown-menu.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}ul.dt-button-collection.dropdown-menu .dt-button{border-radius:0}ul.dt-button-collection{-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}ul.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}ul.dt-button-collection.fixed.two-column{margin-left:-150px}ul.dt-button-collection.fixed.three-column{margin-left:-225px}ul.dt-button-collection.fixed.four-column{margin-left:-300px}ul.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}ul.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}ul.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}ul.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}ul.dt-button-collection .dt-button{border-radius:0}ul.dt-button-collection.fixed{max-width:none}ul.dt-button-collection.fixed:before,ul.dt-button-collection.fixed:after{display:none}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:0.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0,0,0,0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:' ';border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear} diff --git a/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.min.js b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.min.js new file mode 100644 index 0000000..f76a5b0 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.bootstrap4.min.js @@ -0,0 +1,6 @@ +/*! + Bootstrap integration for DataTables' Buttons + ©2016 SpryMedia Ltd - datatables.net/license +*/ +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs4","datatables.net-buttons"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);if(!b||!b.fn.dataTable)b=require("datatables.net-bs4")(a,b).$;b.fn.dataTable.Buttons||require("datatables.net-buttons")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c){var a=c.fn.dataTable;c.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group"}, +button:{className:"btn btn-secondary"},collection:{tag:"div",className:"dt-button-collection dropdown-menu",button:{tag:"a",className:"dt-button dropdown-item",active:"active",disabled:"disabled"}}}});a.ext.buttons.collection.className+=" dropdown-toggle";return a.Buttons}); diff --git a/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.colVis.js b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.colVis.js new file mode 100644 index 0000000..2b71fe3 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.colVis.js @@ -0,0 +1,203 @@ +/*! + * Column visibility buttons for Buttons and DataTables. + * 2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +$.extend( DataTable.ext.buttons, { + // A collection of column visibility buttons + colvis: function ( dt, conf ) { + return { + extend: 'collection', + text: function ( dt ) { + return dt.i18n( 'buttons.colvis', 'Column visibility' ); + }, + className: 'buttons-colvis', + buttons: [ { + extend: 'columnsToggle', + columns: conf.columns, + columnText: conf.columnText + } ] + }; + }, + + // Selected columns with individual buttons - toggle column visibility + columnsToggle: function ( dt, conf ) { + var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) { + return { + extend: 'columnToggle', + columns: idx, + columnText: conf.columnText + }; + } ).toArray(); + + return columns; + }, + + // Single button to toggle column visibility + columnToggle: function ( dt, conf ) { + return { + extend: 'columnVisibility', + columns: conf.columns, + columnText: conf.columnText + }; + }, + + // Selected columns with individual buttons - set column visibility + columnsVisibility: function ( dt, conf ) { + var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) { + return { + extend: 'columnVisibility', + columns: idx, + visibility: conf.visibility, + columnText: conf.columnText + }; + } ).toArray(); + + return columns; + }, + + // Single button to set column visibility + columnVisibility: { + columns: undefined, // column selector + text: function ( dt, button, conf ) { + return conf._columnText( dt, conf ); + }, + className: 'buttons-columnVisibility', + action: function ( e, dt, button, conf ) { + var col = dt.columns( conf.columns ); + var curr = col.visible(); + + col.visible( conf.visibility !== undefined ? + conf.visibility : + ! (curr.length ? curr[0] : false ) + ); + }, + init: function ( dt, button, conf ) { + var that = this; + + dt + .on( 'column-visibility.dt'+conf.namespace, function (e, settings) { + if ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) { + that.active( dt.column( conf.columns ).visible() ); + } + } ) + .on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) { + // Don't rename buttons based on column name if the button + // controls more than one column! + if ( dt.columns( conf.columns ).count() !== 1 ) { + return; + } + + that.text( conf._columnText( dt, conf ) ); + that.active( dt.column( conf.columns ).visible() ); + } ); + + this.active( dt.column( conf.columns ).visible() ); + }, + destroy: function ( dt, button, conf ) { + dt + .off( 'column-visibility.dt'+conf.namespace ) + .off( 'column-reorder.dt'+conf.namespace ); + }, + + _columnText: function ( dt, conf ) { + // Use DataTables' internal data structure until this is presented + // is a public API. The other option is to use + // `$( column(col).node() ).text()` but the node might not have been + // populated when Buttons is constructed. + var idx = dt.column( conf.columns ).index(); + var title = dt.settings()[0].aoColumns[ idx ].sTitle + .replace(/\n/g," ") // remove new lines + .replace(//gi, " ") // replace line breaks with spaces + .replace(//g, "") // remove select tags, including options text + .replace(//g, "") // strip HTML comments + .replace(/<.*?>/g, "") // strip HTML + .replace(/^\s+|\s+$/g,""); // trim + + return conf.columnText ? + conf.columnText( dt, idx, title ) : + title; + } + }, + + + colvisRestore: { + className: 'buttons-colvisRestore', + + text: function ( dt ) { + return dt.i18n( 'buttons.colvisRestore', 'Restore visibility' ); + }, + + init: function ( dt, button, conf ) { + conf._visOriginal = dt.columns().indexes().map( function ( idx ) { + return dt.column( idx ).visible(); + } ).toArray(); + }, + + action: function ( e, dt, button, conf ) { + dt.columns().every( function ( i ) { + // Take into account that ColReorder might have disrupted our + // indexes + var idx = dt.colReorder && dt.colReorder.transpose ? + dt.colReorder.transpose( i, 'toOriginal' ) : + i; + + this.visible( conf._visOriginal[ idx ] ); + } ); + } + }, + + + colvisGroup: { + className: 'buttons-colvisGroup', + + action: function ( e, dt, button, conf ) { + dt.columns( conf.show ).visible( true, false ); + dt.columns( conf.hide ).visible( false, false ); + + dt.columns.adjust(); + }, + + show: [], + + hide: [] + } +} ); + + +return DataTable.Buttons; +})); diff --git a/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.colVis.min.js b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.colVis.min.js new file mode 100644 index 0000000..793b3b2 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.colVis.min.js @@ -0,0 +1,6 @@ +(function(g){"function"===typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(d){return g(d,window,document)}):"object"===typeof exports?module.exports=function(d,f){d||(d=window);if(!f||!f.fn.dataTable)f=require("datatables.net")(d,f).$;f.fn.dataTable.Buttons||require("datatables.net-buttons")(d,f);return g(f,d,d.document)}:g(jQuery,window,document)})(function(g,d,f,h){d=g.fn.dataTable;g.extend(d.ext.buttons,{colvis:function(a,b){return{extend:"collection", +text:function(b){return b.i18n("buttons.colvis","Column visibility")},className:"buttons-colvis",buttons:[{extend:"columnsToggle",columns:b.columns,columnText:b.columnText}]}},columnsToggle:function(a,b){return a.columns(b.columns).indexes().map(function(a){return{extend:"columnToggle",columns:a,columnText:b.columnText}}).toArray()},columnToggle:function(a,b){return{extend:"columnVisibility",columns:b.columns,columnText:b.columnText}},columnsVisibility:function(a,b){return a.columns(b.columns).indexes().map(function(a){return{extend:"columnVisibility", +columns:a,visibility:b.visibility,columnText:b.columnText}}).toArray()},columnVisibility:{columns:h,text:function(a,b,c){return c._columnText(a,c)},className:"buttons-columnVisibility",action:function(a,b,c,e){a=b.columns(e.columns);b=a.visible();a.visible(e.visibility!==h?e.visibility:!(b.length&&b[0]))},init:function(a,b,c){var e=this;a.on("column-visibility.dt"+c.namespace,function(b,d){!d.bDestroying&&d.nTable==a.settings()[0].nTable&&e.active(a.column(c.columns).visible())}).on("column-reorder.dt"+ +c.namespace,function(){1===a.columns(c.columns).count()&&(e.text(c._columnText(a,c)),e.active(a.column(c.columns).visible()))});this.active(a.column(c.columns).visible())},destroy:function(a,b,c){a.off("column-visibility.dt"+c.namespace).off("column-reorder.dt"+c.namespace)},_columnText:function(a,b){var c=a.column(b.columns).index(),e=a.settings()[0].aoColumns[c].sTitle.replace(/\n/g," ").replace(//gi," ").replace(//g,"").replace(//g,"").replace(/<.*?>/g, +"").replace(/^\s+|\s+$/g,"");return b.columnText?b.columnText(a,c,e):e}},colvisRestore:{className:"buttons-colvisRestore",text:function(a){return a.i18n("buttons.colvisRestore","Restore visibility")},init:function(a,b,c){c._visOriginal=a.columns().indexes().map(function(b){return a.column(b).visible()}).toArray()},action:function(a,b,c,d){b.columns().every(function(a){a=b.colReorder&&b.colReorder.transpose?b.colReorder.transpose(a,"toOriginal"):a;this.visible(d._visOriginal[a])})}},colvisGroup:{className:"buttons-colvisGroup", +action:function(a,b,c,d){b.columns(d.show).visible(!0,!1);b.columns(d.hide).visible(!1,!1);b.columns.adjust()},show:[],hide:[]}});return d.Buttons}); diff --git a/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.flash.js b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.flash.js new file mode 100644 index 0000000..5fe50c6 --- /dev/null +++ b/BackEnd/assets/vendor/datatables/extensions/buttons/buttons.flash.js @@ -0,0 +1,1456 @@ +/*! + * Flash export buttons for Buttons and DataTables. + * 2015-2017 SpryMedia Ltd - datatables.net/license + * + * ZeroClipbaord - MIT license + * Copyright (c) 2012 Joseph Huckaby + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * ZeroClipboard dependency + */ + +/* + * ZeroClipboard 1.0.4 with modifications + * Author: Joseph Huckaby + * License: MIT + * + * Copyright (c) 2012 Joseph Huckaby + */ +var ZeroClipboard_TableTools = { + version: "1.0.4-TableTools2", + clients: {}, // registered upload clients on page, indexed by id + moviePath: '', // URL to movie + nextId: 1, // ID of next movie + + $: function(thingy) { + // simple DOM lookup utility function + if (typeof(thingy) == 'string') { + thingy = document.getElementById(thingy); + } + if (!thingy.addClass) { + // extend element with a few useful methods + thingy.hide = function() { this.style.display = 'none'; }; + thingy.show = function() { this.style.display = ''; }; + thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; }; + thingy.removeClass = function(name) { + this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, ''); + }; + thingy.hasClass = function(name) { + return !!this.className.match( new RegExp("\\s*" + name + "\\s*") ); + }; + } + return thingy; + }, + + setMoviePath: function(path) { + // set path to ZeroClipboard.swf + this.moviePath = path; + }, + + dispatch: function(id, eventName, args) { + // receive event from flash movie, send to client + var client = this.clients[id]; + if (client) { + client.receiveEvent(eventName, args); + } + }, + + log: function ( str ) { + console.log( 'Flash: '+str ); + }, + + register: function(id, client) { + // register new client to receive events + this.clients[id] = client; + }, + + getDOMObjectPosition: function(obj) { + // get absolute coordinates for dom element + var info = { + left: 0, + top: 0, + width: obj.width ? obj.width : obj.offsetWidth, + height: obj.height ? obj.height : obj.offsetHeight + }; + + if ( obj.style.width !== "" ) { + info.width = obj.style.width.replace("px",""); + } + + if ( obj.style.height !== "" ) { + info.height = obj.style.height.replace("px",""); + } + + while (obj) { + info.left += obj.offsetLeft; + info.top += obj.offsetTop; + obj = obj.offsetParent; + } + + return info; + }, + + Client: function(elem) { + // constructor for new simple upload client + this.handlers = {}; + + // unique ID + this.id = ZeroClipboard_TableTools.nextId++; + this.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id; + + // register client with singleton to receive flash events + ZeroClipboard_TableTools.register(this.id, this); + + // create movie + if (elem) { + this.glue(elem); + } + } +}; + +ZeroClipboard_TableTools.Client.prototype = { + + id: 0, // unique ID for us + ready: false, // whether movie is ready to receive events or not + movie: null, // reference to movie object + clipText: '', // text to copy to clipboard + fileName: '', // default file save name + action: 'copy', // action to perform + handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor + cssEffects: true, // enable CSS mouse effects on dom container + handlers: null, // user event handlers + sized: false, + sheetName: '', // default sheet name for excel export + + glue: function(elem, title) { + // glue to DOM element + // elem can be ID or actual DOM element object + this.domElement = ZeroClipboard_TableTools.$(elem); + + // float just above object, or zIndex 99 if dom element isn't set + var zIndex = 99; + if (this.domElement.style.zIndex) { + zIndex = parseInt(this.domElement.style.zIndex, 10) + 1; + } + + // find X/Y position of domElement + var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement); + + // create floating DIV above element + this.div = document.createElement('div'); + var style = this.div.style; + style.position = 'absolute'; + style.left = '0px'; + style.top = '0px'; + style.width = (box.width) + 'px'; + style.height = box.height + 'px'; + style.zIndex = zIndex; + + if ( typeof title != "undefined" && title !== "" ) { + this.div.title = title; + } + if ( box.width !== 0 && box.height !== 0 ) { + this.sized = true; + } + + // style.backgroundColor = '#f00'; // debug + if ( this.domElement ) { + this.domElement.appendChild(this.div); + this.div.innerHTML = this.getHTML( box.width, box.height ).replace(/&/g, '&'); + } + }, + + positionElement: function() { + var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement); + var style = this.div.style; + + style.position = 'absolute'; + //style.left = (this.domElement.offsetLeft)+'px'; + //style.top = this.domElement.offsetTop+'px'; + style.width = box.width + 'px'; + style.height = box.height + 'px'; + + if ( box.width !== 0 && box.height !== 0 ) { + this.sized = true; + } else { + return; + } + + var flash = this.div.childNodes[0]; + flash.width = box.width; + flash.height = box.height; + }, + + getHTML: function(width, height) { + // return HTML for movie + var html = ''; + var flashvars = 'id=' + this.id + + '&width=' + width + + '&height=' + height; + + if (navigator.userAgent.match(/MSIE/)) { + // IE gets an OBJECT tag + var protocol = location.href.match(/^https/i) ? 'https://' : 'http://'; + html += ''; + } + else { + // all other browsers get an EMBED tag + html += ''; + } + return html; + }, + + hide: function() { + // temporarily hide floater offscreen + if (this.div) { + this.div.style.left = '-2000px'; + } + }, + + show: function() { + // show ourselves after a call to hide() + this.reposition(); + }, + + destroy: function() { + // destroy control and floater + var that = this; + + if (this.domElement && this.div) { + $(this.div).remove(); + + this.domElement = null; + this.div = null; + + $.each( ZeroClipboard_TableTools.clients, function ( id, client ) { + if ( client === that ) { + delete ZeroClipboard_TableTools.clients[ id ]; + } + } ); + } + }, + + reposition: function(elem) { + // reposition our floating div, optionally to new container + // warning: container CANNOT change size, only position + if (elem) { + this.domElement = ZeroClipboard_TableTools.$(elem); + if (!this.domElement) { + this.hide(); + } + } + + if (this.domElement && this.div) { + var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement); + var style = this.div.style; + style.left = '' + box.left + 'px'; + style.top = '' + box.top + 'px'; + } + }, + + clearText: function() { + // clear the text to be copy / saved + this.clipText = ''; + if (this.ready) { + this.movie.clearText(); + } + }, + + appendText: function(newText) { + // append text to that which is to be copied / saved + this.clipText += newText; + if (this.ready) { this.movie.appendText(newText) ;} + }, + + setText: function(newText) { + // set text to be copied to be copied / saved + this.clipText = newText; + if (this.ready) { this.movie.setText(newText) ;} + }, + + setFileName: function(newText) { + // set the file name + this.fileName = newText; + if (this.ready) { + this.movie.setFileName(newText); + } + }, + + setSheetData: function(data) { + // set the xlsx sheet data + if (this.ready) { + this.movie.setSheetData( JSON.stringify( data ) ); + } + }, + + setAction: function(newText) { + // set action (save or copy) + this.action = newText; + if (this.ready) { + this.movie.setAction(newText); + } + }, + + addEventListener: function(eventName, func) { + // add user event listener for event + // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel + eventName = eventName.toString().toLowerCase().replace(/^on/, ''); + if (!this.handlers[eventName]) { + this.handlers[eventName] = []; + } + this.handlers[eventName].push(func); + }, + + setHandCursor: function(enabled) { + // enable hand cursor (true), or default arrow cursor (false) + this.handCursorEnabled = enabled; + if (this.ready) { + this.movie.setHandCursor(enabled); + } + }, + + setCSSEffects: function(enabled) { + // enable or disable CSS effects on DOM container + this.cssEffects = !!enabled; + }, + + receiveEvent: function(eventName, args) { + var self; + + // receive event from flash + eventName = eventName.toString().toLowerCase().replace(/^on/, ''); + + // special behavior for certain events + switch (eventName) { + case 'load': + // movie claims it is ready, but in IE this isn't always the case... + // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function + this.movie = document.getElementById(this.movieId); + if (!this.movie) { + self = this; + setTimeout( function() { self.receiveEvent('load', null); }, 1 ); + return; + } + + // firefox on pc needs a "kick" in order to set these in certain cases + if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) { + self = this; + setTimeout( function() { self.receiveEvent('load', null); }, 100 ); + this.ready = true; + return; + } + + this.ready = true; + this.movie.clearText(); + this.movie.appendText( this.clipText ); + this.movie.setFileName( this.fileName ); + this.movie.setAction( this.action ); + this.movie.setHandCursor( this.handCursorEnabled ); + break; + + case 'mouseover': + if (this.domElement && this.cssEffects) { + //this.domElement.addClass('hover'); + if (this.recoverActive) { + this.domElement.addClass('active'); + } + } + break; + + case 'mouseout': + if (this.domElement && this.cssEffects) { + this.recoverActive = false; + if (this.domElement.hasClass('active')) { + this.domElement.removeClass('active'); + this.recoverActive = true; + } + //this.domElement.removeClass('hover'); + } + break; + + case 'mousedown': + if (this.domElement && this.cssEffects) { + this.domElement.addClass('active'); + } + break; + + case 'mouseup': + if (this.domElement && this.cssEffects) { + this.domElement.removeClass('active'); + this.recoverActive = false; + } + break; + } // switch eventName + + if (this.handlers[eventName]) { + for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) { + var func = this.handlers[eventName][idx]; + + if (typeof(func) == 'function') { + // actual function reference + func(this, args); + } + else if ((typeof(func) == 'object') && (func.length == 2)) { + // PHP style object + method, i.e. [myObject, 'myMethod'] + func[0][ func[1] ](this, args); + } + else if (typeof(func) == 'string') { + // name of function + window[func](this, args); + } + } // foreach event handler defined + } // user defined handler for event + } +}; + +ZeroClipboard_TableTools.hasFlash = function () +{ + try { + var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); + if (fo) { + return true; + } + } + catch (e) { + if ( + navigator.mimeTypes && + navigator.mimeTypes['application/x-shockwave-flash'] !== undefined && + navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin + ) { + return true; + } + } + + return false; +}; + +// For the Flash binding to work, ZeroClipboard_TableTools must be on the global +// object list +window.ZeroClipboard_TableTools = ZeroClipboard_TableTools; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local (private) functions + */ + +/** + * If a Buttons instance is initlaised before it is placed into the DOM, Flash + * won't be able to bind to it, so we need to wait until it is available, this + * method abstracts that out. + * + * @param {ZeroClipboard} flash ZeroClipboard instance + * @param {jQuery} node Button + */ +var _glue = function ( flash, node ) +{ + var id = node.attr('id'); + + if ( node.parents('html').length ) { + flash.glue( node[0], '' ); + } + else { + setTimeout( function () { + _glue( flash, node ); + }, 500 ); + } +}; + +/** + * Get the sheet name for Excel exports. + * + * @param {object} config Button configuration + */ +var _sheetname = function ( config ) +{ + var sheetName = 'Sheet1'; + + if ( config.sheetName ) { + sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, ''); + } + + return sheetName; +}; + +/** + * Set the flash text. This has to be broken up into chunks as the Javascript / + * Flash bridge has a size limit. There is no indication in the Flash + * documentation what this is, and it probably depends upon the browser. + * Experimentation shows that the point is around 50k when data starts to get + * lost, so an 8K limit used here is safe. + * + * @param {ZeroClipboard} flash ZeroClipboard instance + * @param {string} data Data to send to Flash + */ +var _setText = function ( flash, data ) +{ + var parts = data.match(/[\s\S]{1,8192}/g) || []; + + flash.clearText(); + for ( var i=0, len=parts.length ; i 0 ) { + s += separator; + } + + s += boundary ? + boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary : + a[i]; + } + + return s; + }; + + var header = config.header ? join( data.header )+newLine : ''; + var footer = config.footer && data.footer ? newLine+join( data.footer ) : ''; + var body = []; + + for ( var i=0, ien=data.body.length ; i= 0 ) { + s = String.fromCharCode(n % len + ordA) + s; + n = Math.floor(n / len) - 1; + } + + return s; +} + +/** + * Create an XML node and add any children, attributes, etc without needing to + * be verbose in the DOM. + * + * @param {object} doc XML document + * @param {string} nodeName Node name + * @param {object} opts Options - can be `attr` (attributes), `children` + * (child nodes) and `text` (text content) + * @return {node} Created node + */ +function _createNode( doc, nodeName, opts ){ + var tempNode = doc.createElement( nodeName ); + + if ( opts ) { + if ( opts.attr ) { + $(tempNode).attr( opts.attr ); + } + + if ( opts.children ) { + $.each( opts.children, function ( key, value ) { + tempNode.appendChild( value ); + } ); + } + + if ( opts.text !== null && opts.text !== undefined ) { + tempNode.appendChild( doc.createTextNode( opts.text ) ); + } + } + + return tempNode; +} + +/** + * Get the width for an Excel column based on the contents of that column + * @param {object} data Data for export + * @param {int} col Column index + * @return {int} Column width + */ +function _excelColWidth( data, col ) { + var max = data.header[col].length; + var len, lineSplit, str; + + if ( data.footer && data.footer[col].length > max ) { + max = data.footer[col].length; + } + + for ( var i=0, ien=data.body.length ; i max ) { + max = len; + } + + // Max width rather than having potentially massive column widths + if ( max > 40 ) { + return 52; // 40 * 1.3 + } + } + + max *= 1.3; + + // And a min width + return max > 6 ? max : 6; +} + + var _serialiser = ""; + if (typeof window.XMLSerializer === 'undefined') { + _serialiser = new function () { + this.serializeToString = function (input) { + return input.xml + } + }; + } else { + _serialiser = new XMLSerializer(); + } + + var _ieExcel; + + +/** + * Convert XML documents in an object to strings + * @param {object} obj XLSX document object + */ +function _xlsxToStrings( obj ) { + if ( _ieExcel === undefined ) { + // Detect if we are dealing with IE's _awful_ serialiser by seeing if it + // drop attributes + _ieExcel = _serialiser + .serializeToString( + $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] ) + ) + .indexOf( 'xmlns:r' ) === -1; + } + + $.each( obj, function ( name, val ) { + if ( $.isPlainObject( val ) ) { + _xlsxToStrings( val ); + } + else { + if ( _ieExcel ) { + // IE's XML serialiser will drop some name space attributes from + // from the root node, so we need to save them. Do this by + // replacing the namespace nodes with a regular attribute that + // we convert back when serialised. Edge does not have this + // issue + var worksheet = val.childNodes[0]; + var i, ien; + var attrs = []; + + for ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) { + var attrName = worksheet.attributes[i].nodeName; + var attrValue = worksheet.attributes[i].nodeValue; + + if ( attrName.indexOf( ':' ) !== -1 ) { + attrs.push( { name: attrName, value: attrValue } ); + + worksheet.removeAttribute( attrName ); + } + } + + for ( i=0, ien=attrs.length ; i]*?) xmlns=""([^<>]*?)>/g, '<$1 $2>' ); + + obj[ name ] = str; + } + } ); +} + +// Excel - Pre-defined strings to build a basic XLSX file +var excelStrings = { + "_rels/.rels": + ''+ + ''+ + ''+ + '', + + "xl/_rels/workbook.xml.rels": + ''+ + ''+ + ''+ + ''+ + '', + + "[Content_Types].xml": + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '', + + "xl/workbook.xml": + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '', + + "xl/worksheets/sheet1.xml": + ''+ + ''+ + ''+ + ''+ + '', + + "xl/styles.xml": + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ // Excel appears to use this as a dotted background regardless of values but + ''+ // to be valid to the schema, use a patternFill + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '' +}; +// Note we could use 3 `for` loops for the styles, but when gzipped there is +// virtually no difference in size, since the above can be easily compressed + +// Pattern matching for special number formats. Perhaps this should be exposed +// via an API in future? +var _excelSpecials = [ + { match: /^\-?\d+\.\d%$/, style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p. + { match: /^\-?\d+\.?\d*%$/, style: 56, fmt: function (d) { return d/100; } }, // Percent + { match: /^\-?\$[\d,]+.?\d*$/, style: 57 }, // Dollars + { match: /^\-?£[\d,]+.?\d*$/, style: 58 }, // Pounds + { match: /^\-?€[\d,]+.?\d*$/, style: 59 }, // Euros + { match: /^\([\d,]+\)$/, style: 61, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets + { match: /^\([\d,]+\.\d{2}\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets - 2d.p. + { match: /^[\d,]+$/, style: 63 }, // Numbers with thousand separators + { match: /^[\d,]+\.\d{2}$/, style: 64 } // Numbers with 2d.p. and thousands separators +]; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables options and methods + */ + +// Set the default SWF path +DataTable.Buttons.swfPath = '//cdn.datatables.net/buttons/'+DataTable.Buttons.version+'/swf/flashExport.swf'; + +// Method to allow Flash buttons to be resized when made visible - as they are +// of zero height and width if initialised hidden +DataTable.Api.register( 'buttons.resize()', function () { + $.each( ZeroClipboard_TableTools.clients, function ( i, client ) { + if ( client.domElement !== undefined && client.domElement.parentNode ) { + client.positionElement(); + } + } ); +} ); + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Button definitions + */ + +// Copy to clipboard +DataTable.ext.buttons.copyFlash = $.extend( {}, flashButton, { + className: 'buttons-copy buttons-flash', + + text: function ( dt ) { + return dt.i18n( 'buttons.copy', 'Copy' ); + }, + + action: function ( e, dt, button, config ) { + // Check that the trigger did actually occur due to a Flash activation + if ( ! config._fromFlash ) { + return; + } + + this.processing( true ); + + var flash = config._flash; + var exportData = _exportData( dt, config ); + var info = dt.buttons.exportInfo( config ); + var newline = _newLine(config); + var output = exportData.str; + + if ( info.title ) { + output = info.title + newline + newline + output; + } + + if ( info.messageTop ) { + output = info.messageTop + newline + newline + output; + } + + if ( info.messageBottom ) { + output = output + newline + newline + info.messageBottom; + } + + if ( config.customize ) { + output = config.customize( output, config, dt ); + } + + flash.setAction( 'copy' ); + _setText( flash, output ); + + this.processing( false ); + + dt.buttons.info( + dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), + dt.i18n( 'buttons.copySuccess', { + _: 'Copied %d rows to clipboard', + 1: 'Copied 1 row to clipboard' + }, data.rows ), + 3000 + ); + }, + + fieldSeparator: '\t', + + fieldBoundary: '' +} ); + +// CSV save file +DataTable.ext.buttons.csvFlash = $.extend( {}, flashButton, { + className: 'buttons-csv buttons-flash', + + text: function ( dt ) { + return dt.i18n( 'buttons.csv', 'CSV' ); + }, + + action: function ( e, dt, button, config ) { + // Set the text + var flash = config._flash; + var data = _exportData( dt, config ); + var info = dt.buttons.exportInfo( config ); + var output = config.customize ? + config.customize( data.str, config, dt ) : + data.str; + + flash.setAction( 'csv' ); + flash.setFileName( info.filename ); + _setText( flash, output ); + }, + + escapeChar: '"' +} ); + +// Excel save file - this is really a CSV file using UTF-8 that Excel can read +DataTable.ext.buttons.excelFlash = $.extend( {}, flashButton, { + className: 'buttons-excel buttons-flash', + + text: function ( dt ) { + return dt.i18n( 'buttons.excel', 'Excel' ); + }, + + action: function ( e, dt, button, config ) { + this.processing( true ); + + var flash = config._flash; + var rowPos = 0; + var rels = $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] ) ; //Parses xml + var relsGet = rels.getElementsByTagName( "sheetData" )[0]; + + var xlsx = { + _rels: { + ".rels": $.parseXML( excelStrings['_rels/.rels'] ) + }, + xl: { + _rels: { + "workbook.xml.rels": $.parseXML( excelStrings['xl/_rels/workbook.xml.rels'] ) + }, + "workbook.xml": $.parseXML( excelStrings['xl/workbook.xml'] ), + "styles.xml": $.parseXML( excelStrings['xl/styles.xml'] ), + "worksheets": { + "sheet1.xml": rels + } + + }, + "[Content_Types].xml": $.parseXML( excelStrings['[Content_Types].xml']) + }; + + var data = dt.buttons.exportData( config.exportOptions ); + var currentRow, rowNode; + var addRow = function ( row ) { + currentRow = rowPos+1; + rowNode = _createNode( rels, "row", { attr: {r:currentRow} } ); + + for ( var i=0, ien=row.length ; id&&(d=a.footer[b].length);for(var e=0,f=a.body.length;ed&&(d=c),40'+c),c=c.replace(/_dt_b_namespace_token_/g,":"));c=c.replace(/<([^<>]*?) xmlns=""([^<>]*?)>/g,"<$1 $2>");a[b]=c}})}var j=g.fn.dataTable,h={version:"1.0.4-TableTools2",clients:{},moviePath:"",nextId:1,$:function(a){"string"==typeof a&&(a=l.getElementById(a));a.addClass||(a.hide=function(){this.style.display="none"},a.show=function(){this.style.display= +""},a.addClass=function(a){this.removeClass(a);this.className+=" "+a},a.removeClass=function(a){this.className=this.className.replace(RegExp("\\s*"+a+"\\s*")," ").replace(/^\s+/,"").replace(/\s+$/,"")},a.hasClass=function(a){return!!this.className.match(RegExp("\\s*"+a+"\\s*"))});return a},setMoviePath:function(a){this.moviePath=a},dispatch:function(a,b,d){(a=this.clients[a])&&a.receiveEvent(b,d)},log:function(a){console.log("Flash: "+a)},register:function(a,b){this.clients[a]=b},getDOMObjectPosition:function(a){var b= +{left:0,top:0,width:a.width?a.width:a.offsetWidth,height:a.height?a.height:a.offsetHeight};""!==a.style.width&&(b.width=a.style.width.replace("px",""));""!==a.style.height&&(b.height=a.style.height.replace("px",""));for(;a;)b.left+=a.offsetLeft,b.top+=a.offsetTop,a=a.offsetParent;return b},Client:function(a){this.handlers={};this.id=h.nextId++;this.movieId="ZeroClipboard_TableToolsMovie_"+this.id;h.register(this.id,this);a&&this.glue(a)}};h.Client.prototype={id:0,ready:!1,movie:null,clipText:"",fileName:"", +action:"copy",handCursorEnabled:!0,cssEffects:!0,handlers:null,sized:!1,sheetName:"",glue:function(a,b){this.domElement=h.$(a);var d=99;this.domElement.style.zIndex&&(d=parseInt(this.domElement.style.zIndex,10)+1);var c=h.getDOMObjectPosition(this.domElement);this.div=l.createElement("div");var e=this.div.style;e.position="absolute";e.left="0px";e.top="0px";e.width=c.width+"px";e.height=c.height+"px";e.zIndex=d;"undefined"!=typeof b&&""!==b&&(this.div.title=b);0!==c.width&&0!==c.height&&(this.sized= +!0);this.domElement&&(this.domElement.appendChild(this.div),this.div.innerHTML=this.getHTML(c.width,c.height).replace(/&/g,"&"))},positionElement:function(){var a=h.getDOMObjectPosition(this.domElement),b=this.div.style;b.position="absolute";b.width=a.width+"px";b.height=a.height+"px";0!==a.width&&0!==a.height&&(this.sized=!0,b=this.div.childNodes[0],b.width=a.width,b.height=a.height)},getHTML:function(a,b){var d="",c="id="+this.id+"&width="+a+"&height="+b;if(navigator.userAgent.match(/MSIE/))var e= +location.href.match(/^https/i)?"https://":"http://",d=d+('');else d+='';return d},hide:function(){this.div&&(this.div.style.left="-2000px")}, +show:function(){this.reposition()},destroy:function(){var a=this;this.domElement&&this.div&&(g(this.div).remove(),this.div=this.domElement=null,g.each(h.clients,function(b,d){d===a&&delete h.clients[b]}))},reposition:function(a){a&&((this.domElement=h.$(a))||this.hide());if(this.domElement&&this.div){var a=h.getDOMObjectPosition(this.domElement),b=this.div.style;b.left=""+a.left+"px";b.top=""+a.top+"px"}},clearText:function(){this.clipText="";this.ready&&this.movie.clearText()},appendText:function(a){this.clipText+= +a;this.ready&&this.movie.appendText(a)},setText:function(a){this.clipText=a;this.ready&&this.movie.setText(a)},setFileName:function(a){this.fileName=a;this.ready&&this.movie.setFileName(a)},setSheetData:function(a){this.ready&&this.movie.setSheetData(JSON.stringify(a))},setAction:function(a){this.action=a;this.ready&&this.movie.setAction(a)},addEventListener:function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");this.handlers[a]||(this.handlers[a]=[]);this.handlers[a].push(b)},setHandCursor:function(a){this.handCursorEnabled= +a;this.ready&&this.movie.setHandCursor(a)},setCSSEffects:function(a){this.cssEffects=!!a},receiveEvent:function(a,b){var d,a=a.toString().toLowerCase().replace(/^on/,"");switch(a){case "load":this.movie=l.getElementById(this.movieId);if(!this.movie){d=this;setTimeout(function(){d.receiveEvent("load",null)},1);return}if(!this.ready&&navigator.userAgent.match(/Firefox/)&&navigator.userAgent.match(/Windows/)){d=this;setTimeout(function(){d.receiveEvent("load",null)},100);this.ready=!0;return}this.ready= +!0;this.movie.clearText();this.movie.appendText(this.clipText);this.movie.setFileName(this.fileName);this.movie.setAction(this.action);this.movie.setHandCursor(this.handCursorEnabled);break;case "mouseover":this.domElement&&this.cssEffects&&this.recoverActive&&this.domElement.addClass("active");break;case "mouseout":this.domElement&&this.cssEffects&&(this.recoverActive=!1,this.domElement.hasClass("active")&&(this.domElement.removeClass("active"),this.recoverActive=!0));break;case "mousedown":this.domElement&& +this.cssEffects&&this.domElement.addClass("active");break;case "mouseup":this.domElement&&this.cssEffects&&(this.domElement.removeClass("active"),this.recoverActive=!1)}if(this.handlers[a])for(var c=0,e=this.handlers[a].length;c',"xl/_rels/workbook.xml.rels":'', +"[Content_Types].xml":'', +"xl/workbook.xml":'', +"xl/worksheets/sheet1.xml":'',"xl/styles.xml":''}, +B=[{match:/^\-?\d+\.\d%$/,style:60,fmt:function(a){return a/100}},{match:/^\-?\d+\.?\d*%$/,style:56,fmt:function(a){return a/100}},{match:/^\-?\$[\d,]+.?\d*$/,style:57},{match:/^\-?£[\d,]+.?\d*$/,style:58},{match:/^\-?€[\d,]+.?\d*$/,style:59},{match:/^\([\d,]+\)$/,style:61,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^\([\d,]+\.\d{2}\)$/,style:62,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^[\d,]+$/,style:63},{match:/^[\d,]+\.\d{2}$/,style:64}];j.Buttons.swfPath="//cdn.datatables.net/buttons/"+ +j.Buttons.version+"/swf/flashExport.swf";j.Api.register("buttons.resize()",function(){g.each(h.clients,function(a,b){b.domElement!==q&&b.domElement.parentNode&&b.positionElement()})});j.ext.buttons.copyFlash=g.extend({},u,{className:"buttons-copy buttons-flash",text:function(a){return a.i18n("buttons.copy","Copy")},action:function(a,b,d,c){if(c._fromFlash){this.processing(!0);var a=c._flash,e=A(b,c),d=b.buttons.exportInfo(c),f=z(c),e=e.str;d.title&&(e=d.title+f+f+e);d.messageTop&&(e=d.messageTop+ +f+f+e);d.messageBottom&&(e=e+f+f+d.messageBottom);c.customize&&(e=c.customize(e,c,b));a.setAction("copy");t(a,e);this.processing(!1);b.buttons.info(b.i18n("buttons.copyTitle","Copy to clipboard"),b.i18n("buttons.copySuccess",{_:"Copied %d rows to clipboard",1:"Copied 1 row to clipboard"},data.rows),3E3)}},fieldSeparator:"\t",fieldBoundary:""});j.ext.buttons.csvFlash=g.extend({},u,{className:"buttons-csv buttons-flash",text:function(a){return a.i18n("buttons.csv","CSV")},action:function(a,b,d,c){var a= +c._flash,e=A(b,c),d=b.buttons.exportInfo(c),b=c.customize?c.customize(e.str,c,b):e.str;a.setAction("csv");a.setFileName(d.filename);t(a,b)},escapeChar:'"'});j.ext.buttons.excelFlash=g.extend({},u,{className:"buttons-excel buttons-flash",text:function(a){return a.i18n("buttons.excel","Excel")},action:function(a,b,d,c){this.processing(!0);var a=c._flash,e=0,f=g.parseXML(n["xl/worksheets/sheet1.xml"]),h=f.getElementsByTagName("sheetData")[0],d={_rels:{".rels":g.parseXML(n["_rels/.rels"])},xl:{_rels:{"workbook.xml.rels":g.parseXML(n["xl/_rels/workbook.xml.rels"])}, +"workbook.xml":g.parseXML(n["xl/workbook.xml"]),"styles.xml":g.parseXML(n["xl/styles.xml"]),worksheets:{"sheet1.xml":f}},"[Content_Types].xml":g.parseXML(n["[Content_Types].xml"])},i=b.buttons.exportData(c.exportOptions),k,l,j=function(a){k=e+1;l=o(f,"row",{attr:{r:k}});for(var b=0,d=a.length;b 0 ) { + s += separator; + } + + s += boundary ? + boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary : + a[i]; + } + + return s; + }; + + var header = config.header ? join( data.header )+newLine : ''; + var footer = config.footer && data.footer ? newLine+join( data.footer ) : ''; + var body = []; + + for ( var i=0, ien=data.body.length ; i 1 && version[1]*1 < 603.1 ) { + return true; + } + + return false; +}; + +/** + * Convert from numeric position to letter for column names in Excel + * @param {int} n Column number + * @return {string} Column letter(s) name + */ +function createCellPos( n ){ + var ordA = 'A'.charCodeAt(0); + var ordZ = 'Z'.charCodeAt(0); + var len = ordZ - ordA + 1; + var s = ""; + + while( n >= 0 ) { + s = String.fromCharCode(n % len + ordA) + s; + n = Math.floor(n / len) - 1; + } + + return s; +} + +try { + var _serialiser = new XMLSerializer(); + var _ieExcel; +} +catch (t) {} + +/** + * Recursively add XML files from an object's structure to a ZIP file. This + * allows the XSLX file to be easily defined with an object's structure matching + * the files structure. + * + * @param {JSZip} zip ZIP package + * @param {object} obj Object to add (recursive) + */ +function _addToZip( zip, obj ) { + if ( _ieExcel === undefined ) { + // Detect if we are dealing with IE's _awful_ serialiser by seeing if it + // drop attributes + _ieExcel = _serialiser + .serializeToString( + $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] ) + ) + .indexOf( 'xmlns:r' ) === -1; + } + + $.each( obj, function ( name, val ) { + if ( $.isPlainObject( val ) ) { + var newDir = zip.folder( name ); + _addToZip( newDir, val ); + } + else { + if ( _ieExcel ) { + // IE's XML serialiser will drop some name space attributes from + // from the root node, so we need to save them. Do this by + // replacing the namespace nodes with a regular attribute that + // we convert back when serialised. Edge does not have this + // issue + var worksheet = val.childNodes[0]; + var i, ien; + var attrs = []; + + for ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) { + var attrName = worksheet.attributes[i].nodeName; + var attrValue = worksheet.attributes[i].nodeValue; + + if ( attrName.indexOf( ':' ) !== -1 ) { + attrs.push( { name: attrName, value: attrValue } ); + + worksheet.removeAttribute( attrName ); + } + } + + for ( i=0, ien=attrs.length ; i]*?) xmlns=""([^<>]*?)>/g, '<$1 $2>' ); + + zip.file( name, str ); + } + } ); +} + +/** + * Create an XML node and add any children, attributes, etc without needing to + * be verbose in the DOM. + * + * @param {object} doc XML document + * @param {string} nodeName Node name + * @param {object} opts Options - can be `attr` (attributes), `children` + * (child nodes) and `text` (text content) + * @return {node} Created node + */ +function _createNode( doc, nodeName, opts ) { + var tempNode = doc.createElement( nodeName ); + + if ( opts ) { + if ( opts.attr ) { + $(tempNode).attr( opts.attr ); + } + + if ( opts.children ) { + $.each( opts.children, function ( key, value ) { + tempNode.appendChild( value ); + } ); + } + + if ( opts.text !== null && opts.text !== undefined ) { + tempNode.appendChild( doc.createTextNode( opts.text ) ); + } + } + + return tempNode; +} + +/** + * Get the width for an Excel column based on the contents of that column + * @param {object} data Data for export + * @param {int} col Column index + * @return {int} Column width + */ +function _excelColWidth( data, col ) { + var max = data.header[col].length; + var len, lineSplit, str; + + if ( data.footer && data.footer[col].length > max ) { + max = data.footer[col].length; + } + + for ( var i=0, ien=data.body.length ; i max ) { + max = len; + } + + // Max width rather than having potentially massive column widths + if ( max > 40 ) { + return 52; // 40 * 1.3 + } + } + + max *= 1.3; + + // And a min width + return max > 6 ? max : 6; +} + +// Excel - Pre-defined strings to build a basic XLSX file +var excelStrings = { + "_rels/.rels": + ''+ + ''+ + ''+ + '', + + "xl/_rels/workbook.xml.rels": + ''+ + ''+ + ''+ + ''+ + '', + + "[Content_Types].xml": + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '', + + "xl/workbook.xml": + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '', + + "xl/worksheets/sheet1.xml": + ''+ + ''+ + ''+ + ''+ + '', + + "xl/styles.xml": + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ // Excel appears to use this as a dotted background regardless of values but + ''+ // to be valid to the schema, use a patternFill + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '' +}; +// Note we could use 3 `for` loops for the styles, but when gzipped there is +// virtually no difference in size, since the above can be easily compressed + +// Pattern matching for special number formats. Perhaps this should be exposed +// via an API in future? +// Ref: section 3.8.30 - built in formatters in open spreadsheet +// https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf +var _excelSpecials = [ + { match: /^\-?\d+\.\d%$/, style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p. + { match: /^\-?\d+\.?\d*%$/, style: 56, fmt: function (d) { return d/100; } }, // Percent + { match: /^\-?\$[\d,]+.?\d*$/, style: 57 }, // Dollars + { match: /^\-?£[\d,]+.?\d*$/, style: 58 }, // Pounds + { match: /^\-?€[\d,]+.?\d*$/, style: 59 }, // Euros + { match: /^\-?\d+$/, style: 65 }, // Numbers without thousand separators + { match: /^\-?\d+\.\d{2}$/, style: 66 }, // Numbers 2 d.p. without thousands separators + { match: /^\([\d,]+\)$/, style: 61, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets + { match: /^\([\d,]+\.\d{2}\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets - 2d.p. + { match: /^\-?[\d,]+$/, style: 63 }, // Numbers with thousand separators + { match: /^\-?[\d,]+\.\d{2}$/, style: 64 } // Numbers with 2 d.p. and thousands separators +]; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Buttons + */ + +// +// Copy to clipboard +// +DataTable.ext.buttons.copyHtml5 = { + className: 'buttons-copy buttons-html5', + + text: function ( dt ) { + return dt.i18n( 'buttons.copy', 'Copy' ); + }, + + action: function ( e, dt, button, config ) { + this.processing( true ); + + var that = this; + var exportData = _exportData( dt, config ); + var info = dt.buttons.exportInfo( config ); + var newline = _newLine(config); + var output = exportData.str; + var hiddenDiv = $('
      ') + .css( { + height: 1, + width: 1, + overflow: 'hidden', + position: 'fixed', + top: 0, + left: 0 + } ); + + if ( info.title ) { + output = info.title + newline + newline + output; + } + + if ( info.messageTop ) { + output = info.messageTop + newline + newline + output; + } + + if ( info.messageBottom ) { + output = output + newline + newline + info.messageBottom; + } + + if ( config.customize ) { + output = config.customize( output, config, dt ); + } + + var textarea = $('