identification document validation

This commit is contained in:
jojo aquino 2024-12-23 06:01:06 +00:00
parent e4c217f955
commit 0a4db9e0af
11 changed files with 304 additions and 49 deletions

View File

@ -1,4 +1,5 @@
using EnotaryoPH.Data.Entities; using System.ComponentModel.DataAnnotations;
using EnotaryoPH.Data.Entities;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
@ -29,11 +30,14 @@ namespace EnotaryoPH.Web.Common.Models
[BindProperty] [BindProperty]
public DateTime? ExpirationDate { get; set; } public DateTime? ExpirationDate { get; set; }
[BindProperty] [BindProperty, Required]
public IFormFile? File { get; set; } public IFormFile File { get; set; }
[BindProperty] [BindProperty]
public string Filename { get; set; } public string? Filename { get; set; }
[BindProperty]
public Guid IdentificationDocument_UID { get; set; }
[BindProperty] [BindProperty]
public string IdentificationType { get; set; } public string IdentificationType { get; set; }
@ -48,8 +52,5 @@ namespace EnotaryoPH.Web.Common.Models
[BindProperty] [BindProperty]
public string PlaceIssued { get; set; } public string PlaceIssued { get; set; }
[BindProperty]
public Guid IdentificationDocument_UID { get; set; }
} }
} }

View File

@ -17,7 +17,7 @@ namespace EnotaryoPH.Web.Common.Models
internal static IdentificationDocument ToEntity(this IdentificationDocumentModel model, IdentificationDocument entity) internal static IdentificationDocument ToEntity(this IdentificationDocumentModel model, IdentificationDocument entity)
{ {
ArgumentException.ThrowIfNullOrEmpty(nameof(model.File)); ArgumentNullException.ThrowIfNull(model.File, nameof(model.File));
entity.ExpirationDate = model.ExpirationDate.ToUTC(); entity.ExpirationDate = model.ExpirationDate.ToUTC();
entity.DateIssued = model.DateIssued.ToUTC(); entity.DateIssued = model.DateIssued.ToUTC();

View File

@ -14,5 +14,9 @@
<ProjectReference Include="..\EnotaryoPH.Data\EnotaryoPH.Data.csproj" /> <ProjectReference Include="..\EnotaryoPH.Data\EnotaryoPH.Data.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\lib\jquery.unobtrusive-ajax\" />
</ItemGroup>
</Project> </Project>

View File

@ -21,5 +21,8 @@
</section> </section>
@section Scripts { @section Scripts {
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<partial name="_ValidationScriptsPartial" />
<script src="~/js/identification-document.js"></script> <script src="~/js/identification-document.js"></script>
} }

View File

@ -1,4 +1,5 @@
using EnotaryoPH.Data; using EnotaryoPH.Data;
using EnotaryoPH.Web.Common.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
@ -36,14 +37,7 @@ namespace EnotaryoPH.Web.Pages.Principal.IdentificationDocument
} }
else else
{ {
var defaultImageFilename = $"{_webHostEnvironment.WebRootPath}/images/image-white-on-gray-400x300.jpg"; IdentificationDocument = new Common.Models.IdentificationDocumentModel();
using var stream = new MemoryStream(System.IO.File.ReadAllBytes(defaultImageFilename));
var formFile = new FormFile(stream, 0, stream.Length, "Untitled.jpg", "Untitled.jpg");
IdentificationDocument = new Common.Models.IdentificationDocumentModel
{
File = formFile,
ImageBase64Url = formFile.ToBase64StringUrl()
};
} }
LoadIdentificationDocumentTypes(); LoadIdentificationDocumentTypes();
return Page(); return Page();
@ -78,19 +72,8 @@ namespace EnotaryoPH.Web.Pages.Principal.IdentificationDocument
return BadRequest(); return BadRequest();
} }
} }
entity.ExpirationDate = IdentificationDocument.ExpirationDate.ToUTC();
entity.DateIssued = IdentificationDocument.DateIssued.ToUTC();
entity.PlaceIssued = IdentificationDocument.PlaceIssued;
entity.IdNumber = IdentificationDocument.IdNumber;
entity.Type = IdentificationDocument.IdentificationType;
entity.UploadedOn = DateTime.UtcNow; entity.UploadedOn = DateTime.UtcNow;
entity.UserID = user.UserID; entity = IdentificationDocument.ToEntity(entity);
var file = IdentificationDocument.File;
var stream = new MemoryStream((int)file.Length);
file.CopyTo(stream);
entity.Filename = file.FileName;
entity.File = stream.ToArray();
if (entity.IdentificationDocumentID > 0) if (entity.IdentificationDocumentID > 0)
{ {
@ -98,6 +81,7 @@ namespace EnotaryoPH.Web.Pages.Principal.IdentificationDocument
} }
else else
{ {
entity.UserID = user.UserID;
entity.CreatedOn = DateTime.UtcNow; entity.CreatedOn = DateTime.UtcNow;
entity.IdentificationDocument_UID = Guid.NewGuid(); entity.IdentificationDocument_UID = Guid.NewGuid();
_notaryoDBContext.Add(entity); _notaryoDBContext.Add(entity);
@ -106,17 +90,18 @@ namespace EnotaryoPH.Web.Pages.Principal.IdentificationDocument
return RedirectToPage("/Principal/Dashboard/Dashboard"); return RedirectToPage("/Principal/Dashboard/Dashboard");
} }
private IActionResult PostbackPage() public IActionResult OnPostDeleteIdentificationDocument()
{ {
if (IdentificationDocument.File != null) if (IdentificationDocument_UID == Guid.Empty)
{ {
IdentificationDocument.ImageBase64Url = IdentificationDocument.File.ToBase64StringUrl(); return BadRequest();
//using var stream = IdentificationDocument.File.OpenReadStream();
//IdentificationDocument.File = new FormFile(stream, 0, stream.Length, IdentificationDocument.File.Name, IdentificationDocument.File.Name);
} }
LoadIdentificationDocumentTypes(); var user = _notaryoDBContext.Users.AsNoTracking().FirstOrDefault(u => u.User_UID == _currentUserService.GetUser_UID());
return Page(); _notaryoDBContext.IdentificationDocuments.Remove(_notaryoDBContext.IdentificationDocuments.FirstOrDefault(id => id.IdentificationDocument_UID.Value == IdentificationDocument_UID && id.UserID == user.UserID));
_notaryoDBContext.SaveChanges();
return new OkObjectResult(true);
} }
private void LoadIdentificationDocumentTypes() private void LoadIdentificationDocumentTypes()
@ -130,6 +115,12 @@ namespace EnotaryoPH.Web.Pages.Principal.IdentificationDocument
}); });
} }
private IActionResult PostbackPage()
{
LoadIdentificationDocumentTypes();
return Page();
}
[BindProperty] [BindProperty]
public Common.Models.IdentificationDocumentModel IdentificationDocument { get; set; } public Common.Models.IdentificationDocumentModel IdentificationDocument { get; set; }

View File

@ -4,15 +4,17 @@
} }
<div class="row"> <div class="row">
<div class="col-12 col-lg-4"> <div class="col-12 col-lg-5 col-xl-4">
<div class="card"> <div class="card">
<a href="#" target="_self" class="identification-document__a"><img id="identification-document__a__img" class="identification-document__a__img card-img w-100 d-block fit-cover identification-document__upload__image" src="@Model.ImageBase64Url" style="height: 300px;" /></a> <a href="#" target="_self" class="identification-document__a">
<img id="identification-document__a__img" class="identification-document__a__img card-img w-100 d-block fit-cover identification-document__upload__image" src="@(!string.IsNullOrEmpty(Model.ImageBase64Url) ? Model.ImageBase64Url : "/images/image-white-on-gray-400x300.jpg")" style="height: 300px;" />
</a>
@Html.ValidationMessageFor(m => m.File)
<div class="card-body p-2"> <div class="card-body p-2">
<input type="hidden" asp-for="ImageBase64Url" class="identification-document__base64" /> <input type="hidden" asp-for="ImageBase64Url" class="identification-document__base64" />
<input type="text" asp-for="Filename" class="card-text mb-1 form-control-plaintext identification-document__filename" /> <input type="text" asp-for="Filename" class="card-text mb-1 form-control-plaintext identification-document__filename" />
<div> <div>
<input class="identification-document__upload__file" type="file" style="display:none;" asp-for="File" accept="image/*" /> <input class="identification-document__upload__file" type="file" style="display:none;" asp-for="File" accept="image/*" />
@Html.ValidationMessageFor(m => m.File)
<button class="btn btn-secondary btn-sm me-1 identification-document__upload__button" type="button">Upload Photo<i class="fas fa-upload ms-1"></i></button> <button class="btn btn-secondary btn-sm me-1 identification-document__upload__button" type="button">Upload Photo<i class="fas fa-upload ms-1"></i></button>
</div> </div>
</div> </div>
@ -33,6 +35,7 @@
<div class="mb-3"> <div class="mb-3">
<label class="form-label">ID Number</label> <label class="form-label">ID Number</label>
<input class="form-control form-control" type="text" required asp-for="IdNumber" /> <input class="form-control form-control" type="text" required asp-for="IdNumber" />
@Html.ValidationMessageFor(m => m.IdNumber)
</div> </div>
</div> </div>
</div> </div>
@ -41,6 +44,7 @@
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Place Issued</label> <label class="form-label">Place Issued</label>
<input class="form-control form-control" type="text" required asp-for="PlaceIssued" /> <input class="form-control form-control" type="text" required asp-for="PlaceIssued" />
@Html.ValidationMessageFor(m => m.PlaceIssued)
</div> </div>
</div> </div>
<div class="col-12 col-lg-7"> <div class="col-12 col-lg-7">

View File

@ -1,2 +1,3 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.min.js"></script> <script src="~/lib/jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.min.js"></script>
<script src="~/lib/jquery.unobtrusive-ajax/dist/jquery.unobtrusive-ajax.min.js"></script>

View File

@ -1,13 +1,14 @@
"use strict"; "use strict";
(function () { (function () {
let let
control_deleteButtons = document.querySelectorAll(".identificationdocument__delete__button"),
control_fileInput = document.querySelector(".identification-document__upload__file"), control_fileInput = document.querySelector(".identification-document__upload__file"),
control_uploadButton = document.querySelector(".identification-document__upload__button"),
control_filename = document.querySelector(".identification-document__filename"), control_filename = document.querySelector(".identification-document__filename"),
control_imageLink = document.querySelector(".identification-document__a"),
control_image = document.querySelector(".identification-document__a__img"), control_image = document.querySelector(".identification-document__a__img"),
control_imageBase64Url = document.querySelector(".identification-document__base64"), control_imageBase64Url = document.querySelector(".identification-document__base64"),
x = 1; control_imageLink = document.querySelector(".identification-document__a"),
control_uploadButton = document.querySelector(".identification-document__upload__button")
;
function _bindEvents() { function _bindEvents() {
control_uploadButton.addEventListener("click", function () { control_uploadButton.addEventListener("click", function () {
@ -16,24 +17,42 @@
control_fileInput.addEventListener("change", function (event) { control_fileInput.addEventListener("change", function (event) {
const file = event.target.files[0]; const file = event.target.files[0];
if(file) { if (file) {
console.log('File name:', file.name);
console.log('File size:', file.size);
console.log('File type:', file.type);
control_filename.value = file.name; control_filename.value = file.name;
const reader = new FileReader(); const reader = new FileReader();
reader.onload = function (e) { reader.onload = function (e) {
debugger;
const base64StringUrl = e.target.result; const base64StringUrl = e.target.result;
control_imageLink.href = base64StringUrl; control_imageLink.href = base64StringUrl;
control_image.src = base64StringUrl; control_image.src = base64StringUrl;
console.log('Base64 String:', base64String);
}; };
reader.readAsDataURL(file); reader.readAsDataURL(file);
} else { } else {
console.log('No file selected'); console.log('No file selected');
} }
}); });
control_deleteButtons?.forEach(btn => {
btn.addEventListener("click", _deleteIdentificationDocument);
});
}
function _deleteIdentificationDocument(e) {
jfa.components.dialog.confirm({
message: "Are you sure you want to delete this Identification Document?",
callbackyes: function () {
let btn = e.target.closest("button");
let url = new URL(window.location.origin + '/Principal/IdentificationDocument/IdentificationDocument/' + btn.dataset.uid);
url.searchParams.append("IdentificationDocument_UID", btn.dataset.uid);
url.searchParams.append("handler", "DeleteIdentificationDocument");
jfa.utilities.request.post(url, {})
.then(resp => {
if (resp.ok === true) {
jfa.page.reload();
}
})
.catch(err => console.error(err));
}
});
} }
function _init() { function _init() {
@ -43,8 +62,7 @@
function _initFiles() { function _initFiles() {
if (control_imageBase64Url.value) { if (control_imageBase64Url.value) {
debugger; const fileContent = control_imageBase64Url.value.split(',')[1];
const fileContent = control_imageBase64Url.value;
const filename = control_filename.value; const filename = control_filename.value;
const file = new File([fileContent], filename); const file = new File([fileContent], filename);
const dataTransfer = new DataTransfer(); const dataTransfer = new DataTransfer();

View File

@ -0,0 +1,12 @@
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
these files except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

View File

@ -0,0 +1,205 @@
// Unobtrusive Ajax support library for jQuery
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version <placeholder>
//
// Microsoft grants you the right to use these script files for the sole
// purpose of either: (i) interacting through your browser with the Microsoft
// website or online service, subject to the applicable licensing or use
// terms; or (ii) using the files as included with a Microsoft product subject
// to that product's license terms. Microsoft reserves all other rights to the
// files not expressly granted by Microsoft, whether by implication, estoppel
// or otherwise. Insofar as a script file is dual licensed under GPL,
// Microsoft neither took the code under GPL nor distributes it thereunder but
// under the terms set out in this paragraph. All notices and licenses
// below are for informational purposes only.
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global window: false, jQuery: false */
(function ($) {
var data_click = "unobtrusiveAjaxClick",
data_target = "unobtrusiveAjaxClickTarget",
data_validation = "unobtrusiveValidation";
function getFunction(code, argNames) {
var fn = window, parts = (code || "").split(".");
while (fn && parts.length) {
fn = fn[parts.shift()];
}
if (typeof (fn) === "function") {
return fn;
}
argNames.push(code);
return Function.constructor.apply(null, argNames);
}
function isMethodProxySafe(method) {
return method === "GET" || method === "POST";
}
function asyncOnBeforeSend(xhr, method) {
if (!isMethodProxySafe(method)) {
xhr.setRequestHeader("X-HTTP-Method-Override", method);
}
}
function asyncOnSuccess(element, data, contentType) {
var mode;
if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us
return;
}
mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
$(element.getAttribute("data-ajax-update")).each(function (i, update) {
var top;
switch (mode) {
case "BEFORE":
$(update).prepend(data);
break;
case "AFTER":
$(update).append(data);
break;
case "REPLACE-WITH":
$(update).replaceWith(data);
break;
default:
$(update).html(data);
break;
}
});
}
function asyncRequest(element, options) {
var confirm, loading, method, duration;
confirm = element.getAttribute("data-ajax-confirm");
if (confirm && !window.confirm(confirm)) {
return;
}
loading = $(element.getAttribute("data-ajax-loading"));
duration = parseInt(element.getAttribute("data-ajax-loading-duration"), 10) || 0;
$.extend(options, {
type: element.getAttribute("data-ajax-method") || undefined,
url: element.getAttribute("data-ajax-url") || undefined,
cache: (element.getAttribute("data-ajax-cache") || "").toLowerCase() === "true",
beforeSend: function (xhr) {
var result;
asyncOnBeforeSend(xhr, method);
result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(element, arguments);
if (result !== false) {
loading.show(duration);
}
return result;
},
complete: function () {
loading.hide(duration);
getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(element, arguments);
},
success: function (data, status, xhr) {
asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(element, arguments);
},
error: function () {
getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"]).apply(element, arguments);
}
});
options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });
method = options.type.toUpperCase();
if (!isMethodProxySafe(method)) {
options.type = "POST";
options.data.push({ name: "X-HTTP-Method-Override", value: method });
}
// change here:
// Check for a Form POST with enctype=multipart/form-data
// add the input file that were not previously included in the serializeArray()
// set processData and contentType to false
var $element = $(element);
if ($element.is("form") && $element.attr("enctype") == "multipart/form-data") {
var formdata = new FormData();
$.each(options.data, function (i, v) {
formdata.append(v.name, v.value);
});
$("input[type=file]", $element).each(function () {
var file = this;
$.each(file.files, function (n, v) {
formdata.append(file.name, v);
});
});
$.extend(options, {
processData: false,
contentType: false,
data: formdata
});
}
// end change
$.ajax(options);
}
function validate(form) {
var validationInfo = $(form).data(data_validation);
return !validationInfo || !validationInfo.validate || validationInfo.validate();
}
$(document).on("click", "a[data-ajax=true]", function (evt) {
evt.preventDefault();
asyncRequest(this, {
url: this.href,
type: "GET",
data: []
});
});
$(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) {
var name = evt.target.name,
target = $(evt.target),
form = $(target.parents("form")[0]),
offset = target.offset();
form.data(data_click, [
{ name: name + ".x", value: Math.round(evt.pageX - offset.left) },
{ name: name + ".y", value: Math.round(evt.pageY - offset.top) }
]);
setTimeout(function () {
form.removeData(data_click);
}, 0);
});
$(document).on("click", "form[data-ajax=true] :submit", function (evt) {
var name = evt.currentTarget.name,
target = $(evt.target),
form = $(target.parents("form")[0]);
form.data(data_click, name ? [{ name: name, value: evt.currentTarget.value }] : []);
form.data(data_target, target);
setTimeout(function () {
form.removeData(data_click);
form.removeData(data_target);
}, 0);
});
$(document).on("submit", "form[data-ajax=true]", function (evt) {
var clickInfo = $(this).data(data_click) || [],
clickTarget = $(this).data(data_target),
isCancel = clickTarget && (clickTarget.hasClass("cancel") || clickTarget.attr('formnovalidate') !== undefined);
evt.preventDefault();
if (!isCancel && !validate(this)) {
return;
}
asyncRequest(this, {
url: this.action,
type: this.method || "GET",
data: clickInfo.concat($(this).serializeArray())
});
});
}(jQuery));

View File

@ -0,0 +1,16 @@
// Unobtrusive Ajax support library for jQuery
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version v3.2.6
//
// Microsoft grants you the right to use these script files for the sole
// purpose of either: (i) interacting through your browser with the Microsoft
// website or online service, subject to the applicable licensing or use
// terms; or (ii) using the files as included with a Microsoft product subject
// to that product's license terms. Microsoft reserves all other rights to the
// files not expressly granted by Microsoft, whether by implication, estoppel
// or otherwise. Insofar as a script file is dual licensed under GPL,
// Microsoft neither took the code under GPL nor distributes it thereunder but
// under the terms set out in this paragraph. All notices and licenses
// below are for informational purposes only.
!function(t){function a(t,a){for(var e=window,r=(t||"").split(".");e&&r.length;)e=e[r.shift()];return"function"==typeof e?e:(a.push(t),Function.constructor.apply(null,a))}function e(t){return"GET"===t||"POST"===t}function r(t,a){e(a)||t.setRequestHeader("X-HTTP-Method-Override",a)}function n(a,e,r){var n;r.indexOf("application/x-javascript")===-1&&(n=(a.getAttribute("data-ajax-mode")||"").toUpperCase(),t(a.getAttribute("data-ajax-update")).each(function(a,r){switch(n){case"BEFORE":t(r).prepend(e);break;case"AFTER":t(r).append(e);break;case"REPLACE-WITH":t(r).replaceWith(e);break;default:t(r).html(e)}}))}function i(i,u){var o,c,d,s;if(o=i.getAttribute("data-ajax-confirm"),!o||window.confirm(o)){c=t(i.getAttribute("data-ajax-loading")),s=parseInt(i.getAttribute("data-ajax-loading-duration"),10)||0,t.extend(u,{type:i.getAttribute("data-ajax-method")||void 0,url:i.getAttribute("data-ajax-url")||void 0,cache:"true"===(i.getAttribute("data-ajax-cache")||"").toLowerCase(),beforeSend:function(t){var e;return r(t,d),e=a(i.getAttribute("data-ajax-begin"),["xhr"]).apply(i,arguments),e!==!1&&c.show(s),e},complete:function(){c.hide(s),a(i.getAttribute("data-ajax-complete"),["xhr","status"]).apply(i,arguments)},success:function(t,e,r){n(i,t,r.getResponseHeader("Content-Type")||"text/html"),a(i.getAttribute("data-ajax-success"),["data","status","xhr"]).apply(i,arguments)},error:function(){a(i.getAttribute("data-ajax-failure"),["xhr","status","error"]).apply(i,arguments)}}),u.data.push({name:"X-Requested-With",value:"XMLHttpRequest"}),d=u.type.toUpperCase(),e(d)||(u.type="POST",u.data.push({name:"X-HTTP-Method-Override",value:d}));var p=t(i);if(p.is("form")&&"multipart/form-data"==p.attr("enctype")){var f=new FormData;t.each(u.data,function(t,a){f.append(a.name,a.value)}),t("input[type=file]",p).each(function(){var a=this;t.each(a.files,function(t,e){f.append(a.name,e)})}),t.extend(u,{processData:!1,contentType:!1,data:f})}t.ajax(u)}}function u(a){var e=t(a).data(d);return!e||!e.validate||e.validate()}var o="unobtrusiveAjaxClick",c="unobtrusiveAjaxClickTarget",d="unobtrusiveValidation";t(document).on("click","a[data-ajax=true]",function(t){t.preventDefault(),i(this,{url:this.href,type:"GET",data:[]})}),t(document).on("click","form[data-ajax=true] input[type=image]",function(a){var e=a.target.name,r=t(a.target),n=t(r.parents("form")[0]),i=r.offset();n.data(o,[{name:e+".x",value:Math.round(a.pageX-i.left)},{name:e+".y",value:Math.round(a.pageY-i.top)}]),setTimeout(function(){n.removeData(o)},0)}),t(document).on("click","form[data-ajax=true] :submit",function(a){var e=a.currentTarget.name,r=t(a.target),n=t(r.parents("form")[0]);n.data(o,e?[{name:e,value:a.currentTarget.value}]:[]),n.data(c,r),setTimeout(function(){n.removeData(o),n.removeData(c)},0)}),t(document).on("submit","form[data-ajax=true]",function(a){var e=t(this).data(o)||[],r=t(this).data(c),n=r&&(r.hasClass("cancel")||void 0!==r.attr("formnovalidate"));a.preventDefault(),(n||u(this))&&i(this,{url:this.action,type:this.method||"GET",data:e.concat(t(this).serializeArray())})})}(jQuery);