v1.2.11.3
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -90,7 +90,12 @@ namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
result = ModelBindingResult.Success(value);
|
||||
}
|
||||
}
|
||||
if (result.Model != null && !result.Model.ToString().Equals(result.Model.GetType().FullName) && SaxSystem.DebugMode)
|
||||
// Log property details.
|
||||
if (result.Model != null && SaxSystem.DebugMode &&
|
||||
// Ignore items that correspond with objects in the model rather than values.
|
||||
!result.Model.ToString().Equals(result.Model.GetType().FullName) &&
|
||||
// Ignore form files.
|
||||
!result.Model.ToString().ContainsCI("Microsoft.AspNetCore.Http.IFormFile"))
|
||||
SaLogger.Debug(SysUtil.Fn + " Form property " + modelName + ": '" + result.Model.ToString() + "'." + (originalValue != null && !originalValue.Equals(result.Model) ? " Original value: '" + originalValue.ToString() + "'" : ""));
|
||||
base.SetProperty(bindingContext, modelName, propertyMetadata, result);
|
||||
}
|
||||
|
||||
@@ -120,6 +120,8 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
// Create the upload process.
|
||||
SaxOrganisationUploader.Config processConfig = new SaxOrganisationUploader.Config(SessionContext, model.OrganisationDataFile[0]);
|
||||
processConfig.SheetNameOrNumber = model.SheetNameOrNumber;
|
||||
processConfig.HeaderRowPos = (uint)StringUtil.ToInt(model.HeaderRow);
|
||||
processConfig.FirstDataRowPos = (uint)StringUtil.ToInt(model.FirstDataRow);
|
||||
SaxOrganisationUploader process = new SaxOrganisationUploader(processConfig);
|
||||
|
||||
// Store the process and run.
|
||||
|
||||
@@ -36,7 +36,9 @@ namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
// Organisation data files - only one allowed per request.
|
||||
public List<IFormFile> OrganisationDataFile { get; set; }
|
||||
// Data file properties.
|
||||
public String SheetNameOrNumber { get; set; }
|
||||
public String SheetNameOrNumber { get; set; } = "1";
|
||||
public String HeaderRow { get; set; } = "1";
|
||||
public String FirstDataRow { get; set; } = "2";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
@@ -63,6 +65,24 @@ namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.sheet.name.invalid"]);
|
||||
}
|
||||
|
||||
// Header row position (from 1).
|
||||
{
|
||||
String controlName = nameof(HeaderRow);
|
||||
if (StringUtil.IsBlank(HeaderRow))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!StringUtil.IsNumeric(HeaderRow) || StringUtil.ToInt(HeaderRow) < 1)
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.spreadsheet.row.invalid"]);
|
||||
}
|
||||
|
||||
// First data row position (from 1).
|
||||
{
|
||||
String controlName = nameof(FirstDataRow);
|
||||
if (StringUtil.IsBlank(FirstDataRow))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!StringUtil.IsNumeric(FirstDataRow) || StringUtil.ToInt(FirstDataRow) < 1)
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.spreadsheet.row.invalid"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using EnumsNET;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Proc.Excel;
|
||||
@@ -34,6 +36,7 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
public UploadFileData DataFile { get; }
|
||||
public String SheetNameOrNumber { get; set; }
|
||||
public uint HeaderRowPos { get; set; }
|
||||
public uint FirstDataRowPos { get; set; }
|
||||
public bool ValidateOnly { get; set; }
|
||||
public bool AllowCreateOrganisation { get; set; }
|
||||
public bool RequireOrganisationIdForUpdate { get; set; }
|
||||
@@ -53,28 +56,38 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
// Organisation data profile.
|
||||
private enum OrganisationProperty
|
||||
{
|
||||
// Property columns.
|
||||
OrganisationId, OrganisationName, Sport, Region,
|
||||
// Organisation.
|
||||
OrganisationId, OrganisationName, OrganisationType, OrganisationCategory, Sport, Sports, Region,
|
||||
// Address.
|
||||
AddressLine1, AddressLine2, AddressTown, AddressPostcode,
|
||||
AddressLine1, AddressLine2, AddressTown, AddressProvince, AddressPostcode,
|
||||
// Contact personal.
|
||||
ContactName, ContactRole, ContactEmail,
|
||||
ContactName, ContactRole, ContactNameRole, ContactEmail,
|
||||
// Contact.
|
||||
ContactPhone, ContactWeb, ContactMap, ContactWiki, ContactFacebook, ContactInstagram, ContactTwitter,
|
||||
}
|
||||
private class OrganisationPropertyData
|
||||
private class OrganisationPropertyDfn
|
||||
{
|
||||
public OrganisationPropertyData(OrganisationProperty property, String columnHeaders)
|
||||
public OrganisationPropertyDfn(OrganisationProperty property, String columnHeaders)
|
||||
{
|
||||
this.Property = property;
|
||||
foreach (String value in Regex.Split(columnHeaders, "[\\s,]+", RegexOptions.None))
|
||||
if (!StringUtil.IsBlank(value)) this.ColumnHeaders.Add(value);
|
||||
foreach (String value in Regex.Split(columnHeaders, "(\\s*,\\s*)+", RegexOptions.None))
|
||||
if (!StringUtil.IsBlank(value)) this.ColumnHeaders.Add(StringUtil.TrimWhitespace(value));
|
||||
}
|
||||
public OrganisationProperty Property { get; }
|
||||
public HashSet<String> ColumnHeaders { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
public uint ColumnPos { get; set; }
|
||||
public bool IsValid { get { return ColumnPos > 0; } }
|
||||
}
|
||||
private class OrganisationPropertyData
|
||||
{
|
||||
public OrganisationPropertyData(OrganisationProperty property, DataValue value)
|
||||
{
|
||||
this.Property = property;
|
||||
this.Value = value;
|
||||
}
|
||||
public OrganisationProperty Property { get; }
|
||||
public DataValue Value { get; }
|
||||
}
|
||||
private class OrganisationDataProfile
|
||||
{
|
||||
public OrganisationDataProfile()
|
||||
@@ -82,17 +95,22 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
// Property columns.
|
||||
AddProperty(OrganisationProperty.OrganisationId, "Id, Organisation Id");
|
||||
AddProperty(OrganisationProperty.OrganisationName, "Name, Organisation Name");
|
||||
AddProperty(OrganisationProperty.OrganisationType, "Type, Organisation Type");
|
||||
AddProperty(OrganisationProperty.OrganisationCategory, "Category, Organisation Category");
|
||||
AddProperty(OrganisationProperty.Sport, "Sport");
|
||||
AddProperty(OrganisationProperty.Sports, "Sports");
|
||||
AddProperty(OrganisationProperty.Region, "Region");
|
||||
// Address.
|
||||
AddProperty(OrganisationProperty.AddressLine1, "Address Line 1, Line 1, Street");
|
||||
AddProperty(OrganisationProperty.AddressLine2, "Address Line 2, Line 2");
|
||||
AddProperty(OrganisationProperty.AddressTown, "Town,City,Address Town,Address City");
|
||||
AddProperty(OrganisationProperty.AddressPostcode, "Postcode");
|
||||
AddProperty(OrganisationProperty.AddressProvince, "Province, County, Address Province, Address County");
|
||||
AddProperty(OrganisationProperty.AddressPostcode, "Postcode, Post code, Postal code, Zip code");
|
||||
// Contact personal.
|
||||
AddProperty(OrganisationProperty.ContactName, "Contact Name");
|
||||
AddProperty(OrganisationProperty.ContactRole, "Contact Role");
|
||||
AddProperty(OrganisationProperty.ContactEmail, "Contatc Email");
|
||||
AddProperty(OrganisationProperty.ContactName, "Contact, Contact Name");
|
||||
AddProperty(OrganisationProperty.ContactRole, "Role, Contact Role");
|
||||
AddProperty(OrganisationProperty.ContactNameRole, "Contact & Role, Contact Name & Role");
|
||||
AddProperty(OrganisationProperty.ContactEmail, "Contact Email");
|
||||
// Contact.
|
||||
AddProperty(OrganisationProperty.ContactPhone, "Phone");
|
||||
AddProperty(OrganisationProperty.ContactWeb, "Web, Web Link, Website");
|
||||
@@ -102,35 +120,42 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
AddProperty(OrganisationProperty.ContactInstagram, "Instagram");
|
||||
AddProperty(OrganisationProperty.ContactTwitter, "X, Twitter");
|
||||
}
|
||||
public Dictionary<OrganisationProperty, OrganisationPropertyData> Properties { get; } = new Dictionary<OrganisationProperty, OrganisationPropertyData>();
|
||||
public Dictionary<OrganisationProperty, OrganisationPropertyDfn> Properties { get; } = new Dictionary<OrganisationProperty, OrganisationPropertyDfn>();
|
||||
private void AddProperty(OrganisationProperty property, String columnHeaders)
|
||||
{
|
||||
Properties.Add(property, new OrganisationPropertyData(property, columnHeaders));
|
||||
Properties.Add(property, new OrganisationPropertyDfn(property, columnHeaders));
|
||||
}
|
||||
public bool IsValidProperty(OrganisationProperty property)
|
||||
{
|
||||
OrganisationPropertyData propertyData = Properties[property];
|
||||
return propertyData != null && propertyData.IsValid;
|
||||
OrganisationPropertyDfn propertyDfn = Properties[property];
|
||||
return propertyDfn != null && propertyDfn.IsValid;
|
||||
}
|
||||
public uint FirstDataColPos { get { return Properties.Values.Where(item => item.ColumnPos > 0).Any() ? Properties.Values.Where(item => item.ColumnPos > 0).Select(item => item.ColumnPos).Min() : 1; } }
|
||||
public uint LastDataColPos { get { return Properties.Values.Where(item => item.ColumnPos > 0).Any() ? Properties.Values.Where(item => item.ColumnPos > 0).Select(item => item.ColumnPos).Max() : FirstDataColPos; } }
|
||||
}
|
||||
|
||||
// Processing control data.
|
||||
private class ProcessControlData
|
||||
{
|
||||
public Config config { get; set; }
|
||||
public ProcessControlData(Config config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
public Config config { get; }
|
||||
public SaMsSpreadsheet spreadsheet { get; set; }
|
||||
public OrganisationDataProfile dataProfile { get; } = new OrganisationDataProfile();
|
||||
public List<OrganisationPropertyData> organisationsData { get; } = new List<OrganisationPropertyData>();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private ProcessControlData control { get; } = new ProcessControlData();
|
||||
private ProcessControlData control { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxOrganisationUploader(Config config) : base(config)
|
||||
{
|
||||
control.config = config;
|
||||
control = new ProcessControlData(config);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
@@ -142,19 +167,17 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
// Run the process.
|
||||
protected override bool Run()
|
||||
{
|
||||
String fn = GetType().Name + ".Run";
|
||||
|
||||
// Verify file.
|
||||
if (control.config.DataFile == null)
|
||||
{
|
||||
AddErrorMessage("Data file must be supplied.");
|
||||
SaLogger.Warn(fn + " " + GetErrorMessage());
|
||||
SaLogger.Warn(SysUtil.Fn + " " + GetErrorMessage());
|
||||
return OK;
|
||||
}
|
||||
else if (!validContentTypes.Contains(control.config.DataFile.ContentType))
|
||||
{
|
||||
AddErrorMessage("Unsupported content type: " + control.config.DataFile.ContentType + ".");
|
||||
SaLogger.Warn(fn + " " + GetErrorMessage());
|
||||
SaLogger.Warn(SysUtil.Fn + " " + GetErrorMessage());
|
||||
}
|
||||
AddInfoMessage("Data file: " + control.config.DataFile.FileName);
|
||||
AddInfoMessage("Sheet: " + control.config.SheetNameOrNumber);
|
||||
@@ -173,14 +196,14 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
// Failed to open workbook.
|
||||
String msg = "Failed to open workbook - " + spreadsheet.ErrorStateMessage;
|
||||
AddErrorMessage(msg);
|
||||
SaLogger.Warn(fn + " " + msg);
|
||||
SaLogger.Warn(SysUtil.Fn + " " + msg);
|
||||
}
|
||||
if (OK && !spreadsheet.OpenWorksheet(1))
|
||||
{
|
||||
// Failed to open workbook.
|
||||
String msg = "Failed to open worksheet - " + spreadsheet.ErrorStateMessage;
|
||||
AddErrorMessage(msg);
|
||||
SaLogger.Warn(fn + " " + msg);
|
||||
SaLogger.Warn(SysUtil.Fn + " " + msg);
|
||||
}
|
||||
if (OK)
|
||||
{
|
||||
@@ -188,16 +211,10 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
PopulateDataProfile();
|
||||
}
|
||||
if (OK)
|
||||
{
|
||||
uint firstRowPos = spreadsheet.FirstRowPos;
|
||||
for (uint rowPos = firstRowPos; rowPos <= firstRowPos; rowPos++)
|
||||
{
|
||||
for (uint colPos = 1; colPos <= 5; colPos++)
|
||||
{
|
||||
SaLogger.Info("Row: " + rowPos + ", colPos: " + colPos + ": '" + spreadsheet.GetCellText(colPos, rowPos) + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
LoadOrganisationsData();
|
||||
if (OK)
|
||||
ValidateOrganisationData();
|
||||
|
||||
// Clean-up.
|
||||
control.spreadsheet = null;
|
||||
}
|
||||
@@ -207,44 +224,50 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
{
|
||||
String msg = exc.GetType().Name + " uploading organisation data.";
|
||||
AddErrorMessage(msg);
|
||||
SaLogger.Warn(fn + " " + msg + " " + exc.Message + ExceptionUtil.GetStackEntries(exc, 6).Concat("", "\n\t"));
|
||||
SaLogger.Warn(SysUtil.Fn + " " + msg + " " + exc.Message + ExceptionUtil.GetStackEntries(exc, 6).Concat("", "\n\t"));
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Assign organisation properties to spreadsheet columns.
|
||||
/// </summary>
|
||||
private bool PopulateDataProfile()
|
||||
{
|
||||
String fn = GetType().Name + ".PopulateDataProfile";
|
||||
|
||||
// Identify header row.
|
||||
uint headerRowPos = control.config.HeaderRowPos;
|
||||
if (headerRowPos < 1)
|
||||
headerRowPos = control.spreadsheet.FirstRowPos;
|
||||
|
||||
// Column headings.
|
||||
List<String> columnHeadings = new List<string>();
|
||||
for (uint colPos = 1; colPos <= 100; colPos++)
|
||||
{
|
||||
columnHeadings.Add(control.spreadsheet.GetCellText(colPos, headerRowPos));
|
||||
columnHeadings.Add(control.spreadsheet.GetCellText(colPos, control.config.HeaderRowPos));
|
||||
}
|
||||
SaLogger.Info(fn + " Column headings: " + columnHeadings.Concat(", "));
|
||||
columnHeadings.RemoveTrailingBlanks();
|
||||
SaLogger.Info(SysUtil.Fn + " Column headings: " + columnHeadings.Concat(", "));
|
||||
|
||||
// Populate header columns in profile.
|
||||
foreach (OrganisationPropertyData propertyData in control.dataProfile.Properties.Values)
|
||||
for (uint colPos = 1; colPos <= columnHeadings.Count; colPos++)
|
||||
{
|
||||
for (uint colPos = 1; colPos <= columnHeadings.Count; colPos++)
|
||||
String columnHeading = columnHeadings[(int)(colPos - 1)];
|
||||
if (StringUtil.IsBlank(columnHeading)) continue;
|
||||
|
||||
List<OrganisationPropertyDfn> propertyDfns = control.dataProfile.Properties.Values.Where(item => item.ColumnHeaders.ContainsCI(columnHeading)).ToList();
|
||||
if (propertyDfns.Any())
|
||||
{
|
||||
String columnHeading = columnHeadings[(int)(colPos - 1)];
|
||||
if (propertyData.ColumnHeaders.ContainsCI(columnHeading))
|
||||
// Retrieve the first matching property.
|
||||
OrganisationPropertyDfn propertyDfn = propertyDfns[0];
|
||||
if (propertyDfn.ColumnPos > 0)
|
||||
{
|
||||
if (control.dataProfile.Properties.Values.ToList().Exists(item => item.ColumnPos == colPos))
|
||||
AddWarningMessage("Multiple properties associated with column '" + columnHeading + "'.");
|
||||
propertyData.ColumnPos = colPos;
|
||||
break;
|
||||
AddWarningMessage("Property '" + propertyDfn.Property.GetName() + "' associated with multiple columns.");
|
||||
continue;
|
||||
}
|
||||
// Assign incoming data column to the first property matched by header.
|
||||
propertyDfn.ColumnPos = colPos;
|
||||
if (propertyDfns.Count > 1)
|
||||
AddWarningMessage("Multiple properties associated with organisation column '" + columnHeading + "'.");
|
||||
}
|
||||
else
|
||||
AddWarningMessage("No properties associated with organisation column '" + columnHeading + "'.");
|
||||
}
|
||||
|
||||
if (!control.dataProfile.IsValidProperty(OrganisationProperty.OrganisationId) && !control.dataProfile.IsValidProperty(OrganisationProperty.OrganisationName))
|
||||
@@ -253,6 +276,35 @@ namespace Saxonite.Net.Core.Web.Admin.Procs
|
||||
return OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Load the data from the incoming spreadsheet.
|
||||
/// </summary>
|
||||
private bool LoadOrganisationsData()
|
||||
{
|
||||
// Reset organisation data.
|
||||
control.organisationsData.Clear();
|
||||
|
||||
for (uint rowPos = control.config.FirstDataRowPos; rowPos <= control.spreadsheet.LastRowPos; rowPos++)
|
||||
{
|
||||
List<DataValue> values = control.spreadsheet.GetRowValues(rowPos, (int)control.dataProfile.LastDataColPos);
|
||||
foreach (OrganisationPropertyDfn property in control.dataProfile.Properties.Values)
|
||||
{
|
||||
if (property.ColumnPos < 1) continue;
|
||||
if (property.ColumnPos > values.Count) continue;
|
||||
control.organisationsData.Add(new OrganisationPropertyData(property.Property, values[(int)(property.ColumnPos-1)]));
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private bool ValidateOrganisationData()
|
||||
{
|
||||
List<OrganisationPropertyData> organisationProperties = new List<OrganisationPropertyData>();
|
||||
return OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
|
||||
@@ -321,12 +321,18 @@
|
||||
<data name="label.first" xml:space="preserve">
|
||||
<value>First</value>
|
||||
</data>
|
||||
<data name="label.first.data.row" xml:space="preserve">
|
||||
<value>First data row</value>
|
||||
</data>
|
||||
<data name="label.first.name" xml:space="preserve">
|
||||
<value>First name</value>
|
||||
</data>
|
||||
<data name="label.forgotten.password" xml:space="preserve">
|
||||
<value>Forgotten password?</value>
|
||||
</data>
|
||||
<data name="label.header.row" xml:space="preserve">
|
||||
<value>Header row</value>
|
||||
</data>
|
||||
<data name="label.image" xml:space="preserve">
|
||||
<value>Image</value>
|
||||
</data>
|
||||
@@ -597,6 +603,9 @@
|
||||
<data name="msg.error.sheet.name.invalid" xml:space="preserve">
|
||||
<value>Invalid sheet name supplied.</value>
|
||||
</data>
|
||||
<data name="msg.error.spreadsheet.row.invalid" xml:space="preserve">
|
||||
<value>Spreadsheet row is identified by a number from 1.</value>
|
||||
</data>
|
||||
<data name="msg.error.system" xml:space="preserve">
|
||||
<value>System error encountered.</value>
|
||||
</data>
|
||||
|
||||
@@ -69,7 +69,41 @@
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifSheetNameOrNumber" name="SheetNameOrNumber" class="SheetNameOrNumber sax-input" maxlength="31" />
|
||||
<input type="text" id="ifSheetNameOrNumber" name="SheetNameOrNumber" class="SheetNameOrNumber sax-input" value="1" maxlength="31" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Header row *@
|
||||
<div class="sax-form-control HeaderRow">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifHeaderRow"><span>@Localiser["label.header.row"]</span> <span class="required">*</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifHeaderRow" name="HeaderRow" class="HeaderRow sax-input" value="1" maxlength="2" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* First data row *@
|
||||
<div class="sax-form-control FirstDataRow">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="sax-label">
|
||||
<label for="ifFirstDataRow"><span>@Localiser["label.first.data.row"]</span> <span class="required">*</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="sax-control">
|
||||
<input type="text" id="ifFirstDataRow" name="FirstDataRow" class="FirstDataRow sax-input" value="2" maxlength="2" />
|
||||
</div>
|
||||
<div class="sax-message"></div>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Saxonite.Net.Standard.Base.App
|
||||
//-------------------------------------------------------------------
|
||||
public static class Version
|
||||
{
|
||||
private static String version { get; } = "1.2.11.2";
|
||||
private static String version { get; } = "1.2.11.3";
|
||||
// Retrieve version.
|
||||
public static String GetFullVersion () { return version; }
|
||||
public static String GetAppVersion ()
|
||||
|
||||
@@ -374,6 +374,7 @@ namespace Saxonite.Net.Standard.Base.App
|
||||
Email = 100,
|
||||
Website = 200,
|
||||
Wikipedia = 210,
|
||||
Location = 220,
|
||||
// Social media.
|
||||
LinkedIn = 300,
|
||||
Twitter = 310,
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Saxonite.Net.Standard.Base.Helpers
|
||||
return Sax.ContactMethodType.Email;
|
||||
case Sax.ContactMethod.Website:
|
||||
case Sax.ContactMethod.Wikipedia:
|
||||
case Sax.ContactMethod.Location:
|
||||
case Sax.ContactMethod.LinkedIn:
|
||||
case Sax.ContactMethod.Twitter:
|
||||
case Sax.ContactMethod.Facebook:
|
||||
@@ -58,6 +59,11 @@ namespace Saxonite.Net.Standard.Base.Helpers
|
||||
// Wikipedia.
|
||||
return SacsDataValidationHelper.IsValidWikipediaUrl(value);
|
||||
}
|
||||
else if (method == Sax.ContactMethod.Location)
|
||||
{
|
||||
// Location URL.
|
||||
return SacsDataValidationHelper.IsValidLocationUrl(value);
|
||||
}
|
||||
else if (method == Sax.ContactMethod.LinkedIn)
|
||||
{
|
||||
// LinkedIn.
|
||||
|
||||
Reference in New Issue
Block a user