mirror of
https://github.com/Theodor-Springmann-Stiftung/hamann-ausgabe-core.git
synced 2025-10-29 09:15:33 +00:00
Crated basic file upload method; also included appsettings and feauture-management
This commit is contained in:
26
HaWeb/Controllers/AdminController.cs
Normal file
26
HaWeb/Controllers/AdminController.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace HaWeb.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using HaDocument.Interfaces;
|
||||
using HaXMLReader.Interfaces;
|
||||
using Microsoft.FeatureManagement.Mvc;
|
||||
|
||||
public class AdminController : Controller
|
||||
{
|
||||
// DI
|
||||
private ILibrary _lib;
|
||||
private IReaderService _readerService;
|
||||
|
||||
public AdminController(ILibrary lib, IReaderService readerService)
|
||||
{
|
||||
_lib = lib;
|
||||
_readerService = readerService;
|
||||
}
|
||||
|
||||
|
||||
[Route("Admin")]
|
||||
[FeatureGate(Features.AdminService)]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return Redirect("/Admin/Upload");
|
||||
}
|
||||
}
|
||||
26
HaWeb/Controllers/UpdateController.cs
Normal file
26
HaWeb/Controllers/UpdateController.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace HaWeb.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using HaDocument.Interfaces;
|
||||
using HaXMLReader.Interfaces;
|
||||
using Microsoft.FeatureManagement.Mvc;
|
||||
|
||||
public class UpdateController : Controller
|
||||
{
|
||||
// DI
|
||||
private ILibrary _lib;
|
||||
private IReaderService _readerService;
|
||||
|
||||
public UpdateController(ILibrary lib, IReaderService readerService)
|
||||
{
|
||||
_lib = lib;
|
||||
_readerService = readerService;
|
||||
}
|
||||
|
||||
|
||||
[Route("Admin/Update")]
|
||||
[FeatureGate(Features.UpdateService)]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View("../Admin/Upload/Index");
|
||||
}
|
||||
}
|
||||
115
HaWeb/Controllers/UploadController.cs
Normal file
115
HaWeb/Controllers/UploadController.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
namespace HaWeb.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using HaDocument.Interfaces;
|
||||
using HaXMLReader.Interfaces;
|
||||
using Microsoft.FeatureManagement.Mvc;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using HaWeb.Filters;
|
||||
using HaWeb.FileHelpers;
|
||||
|
||||
public class UploadController : Controller
|
||||
{
|
||||
// DI
|
||||
private ILibrary _lib;
|
||||
private IReaderService _readerService;
|
||||
private readonly long _fileSizeLimit;
|
||||
private readonly string _targetFilePath;
|
||||
|
||||
// Options
|
||||
private static readonly string[] _permittedExtensions = { ".xml" };
|
||||
private static readonly FormOptions _defaultFormOptions = new FormOptions();
|
||||
|
||||
|
||||
public UploadController(ILibrary lib, IReaderService readerService, IConfiguration config)
|
||||
{
|
||||
_lib = lib;
|
||||
_readerService = readerService;
|
||||
_fileSizeLimit = config.GetValue<long>("FileSizeLimit");
|
||||
_targetFilePath = config.GetValue<string>("StoredFilesPath");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Admin/Upload")]
|
||||
[FeatureGate(Features.UploadService)]
|
||||
[GenerateAntiforgeryTokenCookie]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View("../Admin/Upload/Index");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("Admin/Upload")]
|
||||
[DisableFormValueModelBinding]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Post() {
|
||||
|
||||
//// 1. Stage: Check Request and File on a byte-level
|
||||
// Checks the COntent-Type Field (must be multipart + Boundary)
|
||||
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
|
||||
{
|
||||
ModelState.AddModelError("File", $"Wrong / No Content Type on the Request");
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
// Divides the multipart document into it's sections and sets up a reader
|
||||
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
|
||||
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
|
||||
var section = await reader.ReadNextSectionAsync();
|
||||
|
||||
while (section != null)
|
||||
{
|
||||
// Multipart document content disposition header read for a section:
|
||||
// Starts with boundary, contains field name, content-dispo, filename, content-type
|
||||
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
|
||||
|
||||
if (hasContentDispositionHeader && contentDisposition != null)
|
||||
{
|
||||
// Checks if it is a section with content-disposition, name, filename
|
||||
if (!MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
|
||||
{
|
||||
ModelState.AddModelError("File", $"Wrong Content-Dispostion Headers in Multipart Document");
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
// Sanity checks on the file on a byte level, extension checking, is it empty etc.
|
||||
var streamedFileContent = await XMLFileHelpers.ProcessStreamedFile(
|
||||
section, contentDisposition, ModelState,
|
||||
_permittedExtensions, _fileSizeLimit);
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
//// 2. Stage: Valid XML checking
|
||||
|
||||
//// 3. Stage: Is it a Hamann-Document? What kind?
|
||||
|
||||
//// 4. Stage: Get Filename for the stageing area
|
||||
|
||||
//// 5. Stage: Saving the File
|
||||
// // Encode Filename for display
|
||||
// var trustedFileNameForDisplay = WebUtility.HtmlEncode(contentDisposition.FileName.Value);
|
||||
|
||||
|
||||
// // TODO: generatre storage filename
|
||||
// var trustedFileNameForFileStorage = Path.GetRandomFileName();
|
||||
// using (var targetStream = System.IO.File.Create(Path.Combine(_targetFilePath, trustedFileNameForFileStorage)))
|
||||
// await targetStream.WriteAsync(streamedFileContent);
|
||||
}
|
||||
|
||||
// Drain any remaining section body that hasn't been consumed and
|
||||
// read the headers for the next section.
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
|
||||
//// Success! Return Last Created File View
|
||||
return Created(nameof(UploadController), null);
|
||||
}
|
||||
}
|
||||
43
HaWeb/FileHelpers/MultipartRequestHelper.cs
Normal file
43
HaWeb/FileHelpers/MultipartRequestHelper.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace HaWeb.FileHelpers;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
public static class MultipartRequestHelper
|
||||
{
|
||||
// Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq"
|
||||
// The spec at https://tools.ietf.org/html/rfc2046#section-5.1 states that 70 characters is a reasonable limit.
|
||||
public static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit)
|
||||
{
|
||||
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary).Value;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(boundary))
|
||||
throw new InvalidDataException("Missing content-type boundary.");
|
||||
|
||||
if (boundary.Length > lengthLimit)
|
||||
throw new InvalidDataException($"Multipart boundary length limit {lengthLimit} exceeded.");
|
||||
|
||||
return boundary;
|
||||
}
|
||||
|
||||
public static bool IsMultipartContentType(string? contentType)
|
||||
=> !string.IsNullOrEmpty(contentType) && contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
public static bool HasFormDataContentDisposition(ContentDispositionHeaderValue contentDisposition)
|
||||
{
|
||||
// Content-Disposition: form-data; name="key";
|
||||
return contentDisposition != null
|
||||
&& contentDisposition.DispositionType.Equals("form-data")
|
||||
&& string.IsNullOrEmpty(contentDisposition.FileName.Value)
|
||||
&& string.IsNullOrEmpty(contentDisposition.FileNameStar.Value);
|
||||
}
|
||||
|
||||
public static bool HasFileContentDisposition(ContentDispositionHeaderValue? contentDisposition)
|
||||
{
|
||||
return contentDisposition != null
|
||||
&& contentDisposition.DispositionType.Equals("form-data")
|
||||
&& (!string.IsNullOrEmpty(contentDisposition.FileName.Value)
|
||||
|| !string.IsNullOrEmpty(contentDisposition.FileNameStar.Value));
|
||||
}
|
||||
}
|
||||
|
||||
200
HaWeb/FileHelpers/XMLFileHelpers.cs
Normal file
200
HaWeb/FileHelpers/XMLFileHelpers.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
namespace HaWeb.FileHelpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
public static class XMLFileHelpers
|
||||
{
|
||||
// File Signatures Database (https://www.filesignatures.net/)
|
||||
private static readonly Dictionary<string, List<byte[]>> _fileSignature = new Dictionary<string, List<byte[]>>
|
||||
{
|
||||
{ ".gif", new List<byte[]> { new byte[] { 0x47, 0x49, 0x46, 0x38 } } },
|
||||
{ ".png", new List<byte[]> { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A } } },
|
||||
{ ".jpeg", new List<byte[]>
|
||||
{
|
||||
new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
|
||||
new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
|
||||
new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 },
|
||||
}
|
||||
},
|
||||
{ ".jpg", new List<byte[]>
|
||||
{
|
||||
new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
|
||||
new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 },
|
||||
new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 },
|
||||
}
|
||||
},
|
||||
{ ".zip", new List<byte[]>
|
||||
{
|
||||
new byte[] { 0x50, 0x4B, 0x03, 0x04 },
|
||||
new byte[] { 0x50, 0x4B, 0x4C, 0x49, 0x54, 0x45 },
|
||||
new byte[] { 0x50, 0x4B, 0x53, 0x70, 0x58 },
|
||||
new byte[] { 0x50, 0x4B, 0x05, 0x06 },
|
||||
new byte[] { 0x50, 0x4B, 0x07, 0x08 },
|
||||
new byte[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70 },
|
||||
}
|
||||
},
|
||||
{ ".xml", new List<byte[]>
|
||||
{
|
||||
new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x3F, 0x3E },
|
||||
new byte[] { 0xEF, 0xBB, 0xBF, 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x3F, 0x3E },
|
||||
new byte[] { 0xEF, 0xBB, 0xBF, 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x20, 0x65, 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x75, 0x74, 0x66, 0x2D, 0x38, 0x22, 0x3F, 0x3E },
|
||||
new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x20, 0x65, 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x75, 0x74, 0x66, 0x2D, 0x38, 0x22, 0x3F, 0x3E }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Unused as of rn, used to take a file and do the same sanity checks as below
|
||||
// public static async Task<byte[]> ProcessFormFile<T>(IFormFile formFile, ModelStateDictionary modelState, string[] permittedExtensions, long sizeLimit)
|
||||
// {
|
||||
// var fieldDisplayName = string.Empty;
|
||||
|
||||
// // Use reflection to obtain the display name for the model
|
||||
// // property associated with this IFormFile. If a display
|
||||
// // name isn't found, error messages simply won't show
|
||||
// // a display name.
|
||||
// MemberInfo property =
|
||||
// typeof(T).GetProperty(
|
||||
// formFile.Name.Substring(formFile.Name.IndexOf(".",
|
||||
// StringComparison.Ordinal) + 1));
|
||||
|
||||
// if (property != null)
|
||||
// {
|
||||
// if (property.GetCustomAttribute(typeof(DisplayAttribute)) is
|
||||
// DisplayAttribute displayAttribute)
|
||||
// {
|
||||
// fieldDisplayName = $"{displayAttribute.Name} ";
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Don't trust the file name sent by the client. To display
|
||||
// // the file name, HTML-encode the value.
|
||||
// var trustedFileNameForDisplay = WebUtility.HtmlEncode(
|
||||
// formFile.FileName);
|
||||
|
||||
// // Check the file length. This check doesn't catch files that only have
|
||||
// // a BOM as their content.
|
||||
// if (formFile.Length == 0)
|
||||
// {
|
||||
// modelState.AddModelError(formFile.Name,
|
||||
// $"{fieldDisplayName}({trustedFileNameForDisplay}) is empty.");
|
||||
|
||||
// return Array.Empty<byte>();
|
||||
// }
|
||||
|
||||
// if (formFile.Length > sizeLimit)
|
||||
// {
|
||||
// var megabyteSizeLimit = sizeLimit / 1048576;
|
||||
// modelState.AddModelError(formFile.Name,
|
||||
// $"{fieldDisplayName}({trustedFileNameForDisplay}) exceeds " +
|
||||
// $"{megabyteSizeLimit:N1} MB.");
|
||||
|
||||
// return Array.Empty<byte>();
|
||||
// }
|
||||
|
||||
// try
|
||||
// {
|
||||
// using (var memoryStream = new MemoryStream())
|
||||
// {
|
||||
// await formFile.CopyToAsync(memoryStream);
|
||||
|
||||
// // Check the content length in case the file's only
|
||||
// // content was a BOM and the content is actually
|
||||
// // empty after removing the BOM.
|
||||
// if (memoryStream.Length == 0)
|
||||
// {
|
||||
// modelState.AddModelError(formFile.Name,
|
||||
// $"{fieldDisplayName}({trustedFileNameForDisplay}) is empty.");
|
||||
// }
|
||||
|
||||
// if (!IsValidFileExtensionAndSignature(
|
||||
// formFile.FileName, memoryStream, permittedExtensions))
|
||||
// {
|
||||
// modelState.AddModelError(formFile.Name,
|
||||
// $"{fieldDisplayName}({trustedFileNameForDisplay}) file " +
|
||||
// "type isn't permitted or the file's signature " +
|
||||
// "doesn't match the file's extension.");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return memoryStream.ToArray();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// modelState.AddModelError(formFile.Name,
|
||||
// $"{fieldDisplayName}({trustedFileNameForDisplay}) upload failed. " +
|
||||
// $"Please contact the Help Desk for support. Error: {ex.HResult}");
|
||||
// }
|
||||
|
||||
// return Array.Empty<byte>();
|
||||
// }
|
||||
|
||||
public static async Task<byte[]> ProcessStreamedFile(
|
||||
MultipartSection section, ContentDispositionHeaderValue contentDisposition,
|
||||
ModelStateDictionary modelState, string[] permittedExtensions, long sizeLimit)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
await section.Body.CopyToAsync(memoryStream);
|
||||
|
||||
// Check if the file is empty or exceeds the size limit.
|
||||
if (memoryStream.Length == 0)
|
||||
modelState.AddModelError("File", "The file is empty.");
|
||||
else if (memoryStream.Length > sizeLimit)
|
||||
{
|
||||
var megabyteSizeLimit = sizeLimit / 1048576;
|
||||
modelState.AddModelError("File", $"The file exceeds {megabyteSizeLimit:N1} MB.");
|
||||
}
|
||||
|
||||
// Check file extension and first bytes
|
||||
else if (!IsValidFileExtensionAndSignature(contentDisposition.FileName.Value, memoryStream, permittedExtensions))
|
||||
modelState.AddModelError("File", "The file must be of the following specs:<br>" +
|
||||
"1. The file must hava a .xml File-Extension<br>" +
|
||||
"2. To make sure the file isn't executable the file must start with: <?xml version=\"1.0\" encoding=\"utf-8\"?> or <?xml version=\"1.0\"?>");
|
||||
|
||||
// Return the File as a byte array
|
||||
else return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
modelState.AddModelError("File", $"The upload failed. Error: {ex.HResult}");
|
||||
}
|
||||
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
private static bool IsValidFileExtensionAndSignature(string fileName, Stream data, string[] permittedExtensions)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName) || data == null || data.Length == 0)
|
||||
return false;
|
||||
|
||||
var ext = Path.GetExtension(fileName).ToLowerInvariant();
|
||||
|
||||
if (string.IsNullOrEmpty(ext) || !permittedExtensions.Contains(ext))
|
||||
return false;
|
||||
|
||||
data.Position = 0;
|
||||
|
||||
using (var reader = new BinaryReader(data))
|
||||
{
|
||||
var signatures = _fileSignature[ext];
|
||||
var headerBytes = reader.ReadBytes(signatures.Max(m => m.Length));
|
||||
return signatures.Any(signature =>
|
||||
headerBytes.Take(signature.Length).SequenceEqual(signature));
|
||||
}
|
||||
}
|
||||
}
|
||||
27
HaWeb/Filters/Antiforgery.cs
Normal file
27
HaWeb/Filters/Antiforgery.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace HaWeb.Filters;
|
||||
using Microsoft.AspNetCore.Antiforgery;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public class GenerateAntiforgeryTokenCookieAttribute : ResultFilterAttribute
|
||||
{
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
var antiforgery = context.HttpContext.RequestServices.GetService<IAntiforgery>();
|
||||
|
||||
// Send the request token as a JavaScript-readable cookie
|
||||
var tokens = antiforgery.GetAndStoreTokens(context.HttpContext);
|
||||
|
||||
context.HttpContext.Response.Cookies.Append(
|
||||
"RequestVerificationToken",
|
||||
tokens.RequestToken,
|
||||
new CookieOptions() { HttpOnly = false });
|
||||
}
|
||||
|
||||
public override void OnResultExecuted(ResultExecutedContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
20
HaWeb/Filters/ModelBinding.cs
Normal file
20
HaWeb/Filters/ModelBinding.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace HaWeb.Filters;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
||||
{
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
var factories = context.ValueProviderFactories;
|
||||
factories.RemoveType<FormValueProviderFactory>();
|
||||
factories.RemoveType<FormFileValueProviderFactory>();
|
||||
factories.RemoveType<JQueryFormValueProviderFactory>();
|
||||
}
|
||||
|
||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LigerShark.WebOptimizer.Core" Version="3.0.357" />
|
||||
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="2.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using HaXMLReader;
|
||||
using HaXMLReader.Interfaces;
|
||||
using HaDocument.Interfaces;
|
||||
using Microsoft.FeatureManagement;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -9,6 +10,7 @@ builder.Services.AddControllersWithViews();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddSingleton<ILibrary>(x => HaDocument.Document.Create(new Options()));
|
||||
builder.Services.AddTransient<IReaderService, ReaderService>();
|
||||
builder.Services.AddFeatureManagement();
|
||||
|
||||
// builder.Services.AddWebOptimizer();
|
||||
|
||||
@@ -26,10 +28,11 @@ if (!app.Environment.IsDevelopment())
|
||||
// app.UseWebOptimizer();
|
||||
app.UseAuthorization();
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
|
||||
|
||||
|
||||
class Options : IHaDocumentOptions {
|
||||
public string HamannXMLFilePath { get; set; } = HaWeb.Settings.General.XMLFILEPATH;
|
||||
public string[] AvailableVolumes { get; set; } = HaWeb.Settings.General.AVAILABLEVOLUMES;
|
||||
|
||||
@@ -35,8 +35,10 @@ Briefe beim Namen
|
||||
|
||||
- GND Normdaten der Namen
|
||||
|
||||
|
||||
TODO tabellen ok, ausser 939: dort sind htabs geschachtelt
|
||||
TODO 1127 zu breit
|
||||
TODO tabellen ok, ausser 939, 806 falsch geschachtelt: dort sind htabs geschachtelt
|
||||
TODO 659 align center und align-right ueberschneidugn
|
||||
TODO Kommentare und min-size von ha-lettertetx
|
||||
TODO Word-wrap before align, tabs
|
||||
TODO blinken before js
|
||||
|
||||
TODO pills are not mobile friendly (hover / click)
|
||||
TODO Evtl alignment von center / right an der letzten oder nächsten zeile
|
||||
8
HaWeb/Settings/Features.cs
Normal file
8
HaWeb/Settings/Features.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace HaWeb;
|
||||
|
||||
public static class Features
|
||||
{
|
||||
public const string AdminService = "AdminService";
|
||||
public const string UploadService = "UploadService";
|
||||
public const string UpdateService = "UpdateService";
|
||||
}
|
||||
0
HaWeb/Views/Admin/Index.cshtml
Normal file
0
HaWeb/Views/Admin/Index.cshtml
Normal file
57
HaWeb/Views/Admin/Upload/Index.cshtml
Normal file
57
HaWeb/Views/Admin/Upload/Index.cshtml
Normal file
@@ -0,0 +1,57 @@
|
||||
Hello from Upload Index!
|
||||
|
||||
<form id="uploadForm" action="Upload" method="post"
|
||||
enctype="multipart/form-data" onsubmit="AJAXSubmit(this);return false;">
|
||||
<dl>
|
||||
<dt>
|
||||
<label for="file">File</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<input id="file" type="file" name="file" />
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<input class="btn" type="submit" value="Upload" />
|
||||
|
||||
<div style="margin-top:15px">
|
||||
<output form="uploadForm" name="result"></output>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
|
||||
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
|
||||
asp-fallback-test="window.jQuery"
|
||||
crossorigin="anonymous"
|
||||
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
|
||||
</script>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
async function AJAXSubmit (oFormElement) {
|
||||
const formData = new FormData(oFormElement);
|
||||
|
||||
try {
|
||||
const response = await fetch(oFormElement.action, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'RequestVerificationToken': getCookie('RequestVerificationToken')
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
|
||||
oFormElement.elements.namedItem("result").value =
|
||||
'Result: ' + response.status + ' ' + response.statusText;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var value = "; " + document.cookie;
|
||||
var parts = value.split("; " + name + "=");
|
||||
if (parts.length == 2) return parts.pop().split(";").shift();
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@@ -45,6 +45,8 @@
|
||||
<environment exclude="Development">
|
||||
@await Html.PartialAsync("/Views/Shared/_Javascript.cshtml")
|
||||
</environment>
|
||||
|
||||
@RenderSection("Scripts", required: false)
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -5,5 +5,12 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
"FeatureManagement": {
|
||||
"AdminService": true,
|
||||
"UploadService": true,
|
||||
"UpdateService": false
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"StoredFilesPath": "/home/simon/Downloads/",
|
||||
"FileSizeLimit": 209799152
|
||||
}
|
||||
|
||||
@@ -682,15 +682,7 @@ body {
|
||||
color: rgb(229 231 235 / var(--tw-text-opacity)) !important;
|
||||
}
|
||||
|
||||
.ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks, .ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-letlinks {
|
||||
border-left-width: 2px;
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(203 213 225 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks, .dark .ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-letlinks {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(100 116 139 / var(--tw-border-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(15 23 42 / var(--tw-bg-opacity));
|
||||
--tw-text-opacity: 1;
|
||||
@@ -704,12 +696,28 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks::before, .ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-letlinks::before {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(148 163 184 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks::before, .dark .ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-letlinks::before {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(100 116 139 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.ha-register .ha-register-body .ha-commenthead .ha-letlinks.ha-expanded-box {
|
||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.dark .ha-register .ha-register-body .ha-commenthead .ha-letlinks.ha-expanded-box {
|
||||
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ha-register .ha-btn-collapsed-box {
|
||||
position: absolute;
|
||||
top: -0.15rem;
|
||||
@@ -813,12 +821,14 @@ body {
|
||||
.ha-letterheader {
|
||||
border-bottom-width: 2px;
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(226 232 240 / var(--tw-border-opacity));
|
||||
border-color: rgb(203 213 225 / var(--tw-border-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(248 250 252 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-letterheader {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(248 250 252 / var(--tw-border-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(15 23 42 / var(--tw-bg-opacity));
|
||||
--tw-text-opacity: 1;
|
||||
@@ -849,14 +859,16 @@ body {
|
||||
}
|
||||
|
||||
.ha-letterheader .ha-lettertabs a.active {
|
||||
border-bottom-width: 2px;
|
||||
border-bottom-width: 3px;
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(226 232 240 / var(--tw-border-opacity));
|
||||
border-color: rgb(203 213 225 / var(--tw-border-opacity));
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(216 0 0 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-letterheader .ha-lettertabs a.active {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(248 250 252 / var(--tw-border-opacity));
|
||||
font-weight: 700;
|
||||
--tw-text-opacity: 1 !important;
|
||||
color: rgb(229 231 235 / var(--tw-text-opacity)) !important;
|
||||
@@ -932,6 +944,7 @@ body {
|
||||
}
|
||||
|
||||
.ha-additions {
|
||||
display: none;
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(248 250 252 / var(--tw-bg-opacity));
|
||||
}
|
||||
@@ -1000,11 +1013,18 @@ body {
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox.ha-expanded-box .ha-marginallist, .ha-lettertext .ha-marginalbox.ha-expanded-box .ha-marginallist {
|
||||
padding-bottom: 0.25rem;
|
||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.dark .ha-tradzhtext .ha-marginalbox.ha-expanded-box .ha-marginallist, .dark .ha-lettertext .ha-marginalbox.ha-expanded-box .ha-marginallist {
|
||||
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-btn-collapsed-box, .ha-lettertext .ha-btn-collapsed-box {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(51 65 85 / var(--tw-text-opacity));
|
||||
@@ -1025,50 +1045,42 @@ body {
|
||||
color: rgb(229 231 235 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.ha-added, .ha-added
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-added, .ha-added *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(203 213 225 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-added, .dark .ha-added
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.dark .ha-added, .dark .ha-added *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(71 85 105 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.ha-note, .ha-note
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-note, .ha-note *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(51 65 85 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-note, .dark .ha-note
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.dark .ha-note, .dark .ha-note *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(100 116 139 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.ha-ful, .ha-ful * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-ful, .ha-ful *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(0 0 0 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-ful, .dark .ha-ful * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.dark .ha-ful, .dark .ha-ful *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(255 255 255 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.ha-tul, .ha-tul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-tul, .ha-tul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(0 0 0 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.dark .ha-tul, .dark .ha-tul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.dark .ha-tul, .dark .ha-tul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(255 255 255 / var(--tw-border-opacity));
|
||||
}
|
||||
@@ -1610,6 +1622,16 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks::before {
|
||||
position: absolute;
|
||||
top: 0.1rem;
|
||||
bottom: 0.1rem;
|
||||
left: 0px;
|
||||
width: 0.125rem;
|
||||
--tw-content: '';
|
||||
content: var(--tw-content);
|
||||
}
|
||||
|
||||
.ha-register
|
||||
.ha-register-body
|
||||
.ha-comment
|
||||
@@ -1868,6 +1890,7 @@ body {
|
||||
.ha-lettertext {
|
||||
position: relative;
|
||||
margin-left: 1rem;
|
||||
display: flow-root;
|
||||
max-width: 38rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
@@ -1894,6 +1917,7 @@ body {
|
||||
.ha-marginals {
|
||||
position: relative;
|
||||
margin-left: 1rem;
|
||||
display: none;
|
||||
max-width: 48rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
@@ -1986,7 +2010,7 @@ body {
|
||||
.ha-additions .ha-tradition .ha-tradzhtext {
|
||||
position: relative;
|
||||
margin-left: -1rem;
|
||||
display: block !important;
|
||||
display: flow-root !important;
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
@@ -2126,19 +2150,11 @@ body {
|
||||
|
||||
@media (min-width: 700px) {
|
||||
.ha-linecount.ha-firstline {
|
||||
left: -4rem;
|
||||
display: inline-block;
|
||||
max-width: 5rem;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1190px) {
|
||||
.ha-linecount.ha-firstline {
|
||||
left: -5.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ha-linecount {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
@@ -2152,9 +2168,9 @@ body {
|
||||
@media (min-width: 700px) {
|
||||
.ha-linecount {
|
||||
position: absolute;
|
||||
left: -8.6rem;
|
||||
right: 100%;
|
||||
margin-right: 0.5rem;
|
||||
margin-top: 0.25rem;
|
||||
width: 8rem;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
@@ -2196,7 +2212,7 @@ body {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginal::before, .ha-lettertext .ha-marginal:before {
|
||||
.ha-tradzhtext .ha-marginal::before, .ha-lettertext .ha-marginal::before {
|
||||
position: absolute;
|
||||
top: 0.1rem;
|
||||
bottom: 0.1rem;
|
||||
@@ -2219,9 +2235,6 @@ body {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
line-height: 1.25;
|
||||
-webkit-hyphens: auto;
|
||||
-ms-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
@@ -2239,8 +2252,8 @@ body {
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist, .ha-lettertext .ha-marginalbox .ha-marginallist {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
-moz-column-gap: 1rem;
|
||||
column-gap: 1rem;
|
||||
-moz-column-gap: 1.5rem;
|
||||
column-gap: 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
line-height: 1.25;
|
||||
@@ -2249,7 +2262,6 @@ body {
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist .ha-marginal, .ha-lettertext .ha-marginalbox .ha-marginallist .ha-marginal {
|
||||
position: relative;
|
||||
display: inline;
|
||||
flex-grow: 1;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -2265,6 +2277,13 @@ body {
|
||||
text-decoration-style: solid;
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist .ha-marginal, .ha-lettertext .ha-marginalbox .ha-marginallist .ha-marginal, .ha-tradzhtext .ha-marginalbox .ha-marginallist .ha-marginal *, .ha-lettertext .ha-marginalbox .ha-marginallist .ha-marginal * {
|
||||
min-height: 0px;
|
||||
min-width: 0px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-btn-collapsed-box, .ha-lettertext .ha-btn-collapsed-box {
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
@@ -2347,47 +2366,41 @@ body {
|
||||
font-family: Libertine, serif;
|
||||
}
|
||||
|
||||
.ha-aq, .ha-aq * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-aq, .ha-aq *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
font-family: Biolinum, sans-serif;
|
||||
}
|
||||
|
||||
.ha-ul, .ha-ul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-ul, .ha-ul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
-webkit-text-decoration-line: underline;
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.ha-del, .ha-del * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal, .ha-diagdel) {
|
||||
.ha-del, .ha-del *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-diagdel, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
display: inline;
|
||||
-webkit-text-decoration-line: line-through;
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
|
||||
.ha-hand, .ha-hand
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-hand, .ha-hand *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
font-family: Playfair, serif;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.ha-added, .ha-added
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-added, .ha-added *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
border-radius: 0.125rem;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.ha-note, .ha-note
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-note, .ha-note *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.ha-emph {
|
||||
.ha-emph *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.ha-sup {
|
||||
.ha-sup *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
position: relative;
|
||||
top: -0.3em;
|
||||
font-size: 80%;
|
||||
@@ -2414,20 +2427,20 @@ body {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ha-ful, .ha-ful * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-ful, .ha-ful *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
display: inline;
|
||||
border-bottom-width: 1px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.ha-dul, .ha-dul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-dul, .ha-dul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
-webkit-text-decoration-line: underline;
|
||||
text-decoration-line: underline;
|
||||
-webkit-text-decoration-style: double;
|
||||
text-decoration-style: double;
|
||||
}
|
||||
|
||||
.ha-tul, .ha-tul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-tul, .ha-tul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
border-bottom-width: 3px;
|
||||
border-style: double;
|
||||
-webkit-text-decoration-line: underline;
|
||||
@@ -2670,8 +2683,10 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.ha-collapsed-box {
|
||||
.ha-collapsed-box, .ha-collapsed-box * {
|
||||
z-index: 0;
|
||||
min-height: 0px;
|
||||
min-width: 0px;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -2684,11 +2699,6 @@ body {
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
/* .ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-collapsed-box:hover,
|
||||
.ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-collapsed-box:hover {
|
||||
@apply shadow-md z-[1000] !h-auto
|
||||
} */
|
||||
|
||||
.pointer-events-none {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -2757,6 +2767,10 @@ body {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.flow-root {
|
||||
display: flow-root;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -3073,6 +3087,12 @@ body {
|
||||
list-style-type:circle;
|
||||
} */
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox.ha-collapsed-box .ha-marginallist .ha-marginal,
|
||||
.ha-lettertext .ha-marginalbox.ha-collapsed-box .ha-marginallist .ha-marginal {
|
||||
display: -webkit-inline-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.ha-diagdel {
|
||||
text-decoration: none !important;
|
||||
-webkit-text-decoration-line: none !important;
|
||||
@@ -3098,7 +3118,7 @@ body {
|
||||
}
|
||||
|
||||
.ha-del .ha-del,
|
||||
.ha-del .ha-del * {
|
||||
.ha-del .ha-del *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
-moz-text-decoration-style: double;
|
||||
-webkit-text-decoration-style: double !important;
|
||||
text-decoration-thickness: 1px;
|
||||
|
||||
@@ -168,11 +168,16 @@
|
||||
|
||||
.ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks,
|
||||
.ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-letlinks {
|
||||
@apply desktop:bg-slate-50 dark:bg-slate-900 dark:text-slate-50 border-l-2 border-slate-300 dark:border-slate-500
|
||||
@apply desktop:bg-slate-50 dark:bg-slate-900 dark:text-slate-50
|
||||
}
|
||||
|
||||
.ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks::before,
|
||||
.ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-letlinks::before {
|
||||
@apply bg-slate-400 dark:bg-slate-500
|
||||
}
|
||||
|
||||
.ha-register .ha-register-body .ha-commenthead .ha-letlinks.ha-expanded-box {
|
||||
@apply shadow-md
|
||||
@apply shadow-md dark:shadow-lg
|
||||
}
|
||||
|
||||
.ha-register .ha-btn-collapsed-box {
|
||||
@@ -213,7 +218,7 @@
|
||||
}
|
||||
|
||||
.ha-letterheader {
|
||||
@apply bg-slate-50 dark:bg-slate-900 dark:text-slate-50 border-slate-200 border-b-2 dark:shadow-xl
|
||||
@apply bg-slate-50 dark:bg-slate-900 dark:text-slate-50 border-slate-300 dark:border-slate-50 border-b-2 dark:shadow-xl
|
||||
}
|
||||
|
||||
.ha-letterheader .ha-lettertabs a {
|
||||
@@ -221,7 +226,7 @@
|
||||
}
|
||||
|
||||
.ha-letterheader .ha-lettertabs a.active {
|
||||
@apply border-b-2 border-slate-200 text-hamannHighlight dark:!text-gray-200 dark:font-bold
|
||||
@apply border-b-[3px] border-slate-300 dark:border-slate-50 text-hamannHighlight dark:!text-gray-200 dark:font-bold
|
||||
}
|
||||
|
||||
.ha-letterheader .ha-lettermetalinks {
|
||||
@@ -245,7 +250,7 @@
|
||||
}
|
||||
|
||||
.ha-additions {
|
||||
@apply bg-slate-50 dark:bg-slate-900
|
||||
@apply hidden bg-slate-50 dark:bg-slate-900
|
||||
}
|
||||
|
||||
.ha-additions .ha-edits .ha-editentries table tr:nth-child(even) {
|
||||
@@ -273,7 +278,7 @@
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox.ha-expanded-box .ha-marginallist,
|
||||
.ha-lettertext .ha-marginalbox.ha-expanded-box .ha-marginallist {
|
||||
@apply shadow-md
|
||||
@apply shadow-md dark:shadow-lg pb-1
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-btn-collapsed-box,
|
||||
@@ -282,26 +287,22 @@
|
||||
}
|
||||
|
||||
.ha-added,
|
||||
.ha-added
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-added *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
@apply bg-slate-300 dark:bg-slate-600
|
||||
}
|
||||
|
||||
.ha-note,
|
||||
.ha-note
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-note *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
@apply text-slate-700 dark:text-slate-500
|
||||
}
|
||||
|
||||
.ha-ful,
|
||||
.ha-ful * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-ful *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
@apply border-black dark:border-white
|
||||
}
|
||||
|
||||
.ha-tul,
|
||||
.ha-tul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-tul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
@apply border-black dark:border-white
|
||||
}
|
||||
|
||||
@@ -541,6 +542,10 @@
|
||||
@apply inline-block font-normal text-xs md:text-sm leading-snug font-sans caps-allpetite ml-2
|
||||
}
|
||||
|
||||
.ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks::before {
|
||||
@apply absolute top-[0.1rem] bottom-[0.1rem] left-0 w-0.5 content-['']
|
||||
}
|
||||
|
||||
.ha-register
|
||||
.ha-register-body
|
||||
.ha-comment
|
||||
@@ -711,11 +716,11 @@
|
||||
}
|
||||
|
||||
.ha-lettertext {
|
||||
@apply max-w-[38rem] desktop:max-w-[45rem] sm:shrink-0 ml-4 sm:ml-12 px-4 pt-4 pb-8 relative font-serif leading-[1.48] numeric-mediaeval
|
||||
@apply max-w-[38rem] desktop:max-w-[45rem] sm:shrink-0 ml-4 sm:ml-12 px-4 pt-4 pb-8 relative flow-root font-serif leading-[1.48] numeric-mediaeval
|
||||
}
|
||||
|
||||
.ha-marginals {
|
||||
@apply max-w-3xl ml-4 md:ml-12 px-4 py-4 relative leading-[1.48] numeric-mediaeval
|
||||
@apply hidden max-w-3xl ml-4 md:ml-12 px-4 py-4 relative leading-[1.48] numeric-mediaeval
|
||||
}
|
||||
|
||||
.ha-marginals table td {
|
||||
@@ -763,7 +768,7 @@
|
||||
}
|
||||
|
||||
.ha-additions .ha-tradition .ha-tradzhtext {
|
||||
@apply !block font-serif relative w-fit -ml-4 pl-4 unhyphenate
|
||||
@apply !flow-root font-serif relative w-fit -ml-4 pl-4 unhyphenate
|
||||
}
|
||||
|
||||
.ha-additions .ha-tradition a {
|
||||
@@ -857,11 +862,11 @@
|
||||
}
|
||||
|
||||
.ha-linecount.ha-firstline {
|
||||
@apply hidden sm:inline-block rounded px-1 sm:pb-1 caps-allpetite normal-nums sm:max-w-[5rem] whitespace-nowrap sm:-left-[4rem] desktop:-left-[5.5rem]
|
||||
@apply hidden sm:inline-block rounded px-1 sm:pb-1 caps-allpetite normal-nums whitespace-nowrap
|
||||
}
|
||||
|
||||
.ha-linecount {
|
||||
@apply sm:absolute sm:-left-[8.6rem] sm:text-right sm:w-32 text-xs sm:mt-1 font-sans select-none
|
||||
@apply sm:absolute sm:right-full sm:mr-2 sm:text-right text-xs sm:mt-1 font-sans select-none
|
||||
}
|
||||
|
||||
.ha-linecount .ha-zhline {
|
||||
@@ -882,23 +887,23 @@
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginal::before,
|
||||
.ha-lettertext .ha-marginal:before {
|
||||
.ha-lettertext .ha-marginal::before {
|
||||
@apply absolute top-[0.1rem] bottom-[0.1rem] left-0 w-0.5 content-['']
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox,
|
||||
.ha-lettertext .ha-marginalbox {
|
||||
@apply hidden pl-2 md:block absolute left-full ml-6 mt-1 w-[16rem] desktop:w-[24rem] text-sm leading-tight hyphenate rounded-sm font-sans
|
||||
@apply hidden pl-2 md:block absolute left-full ml-6 mt-1 w-[16rem] desktop:w-[24rem] text-sm leading-tight rounded-sm font-sans
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist,
|
||||
.ha-lettertext .ha-marginalbox .ha-marginallist {
|
||||
@apply text-sm leading-tight flex flex-wrap gap-x-4
|
||||
@apply text-sm leading-tight flex flex-wrap gap-x-6
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist .ha-marginal,
|
||||
.ha-lettertext .ha-marginalbox .ha-marginallist .ha-marginal {
|
||||
@apply pl-2 inline grow relative
|
||||
@apply pl-2 inline relative
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist .ha-marginal a,
|
||||
@@ -906,6 +911,13 @@
|
||||
@apply !underline decoration-dotted hover:decoration-solid
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist .ha-marginal,
|
||||
.ha-lettertext .ha-marginalbox .ha-marginallist .ha-marginal,
|
||||
.ha-tradzhtext .ha-marginalbox .ha-marginallist .ha-marginal *,
|
||||
.ha-lettertext .ha-marginalbox .ha-marginallist .ha-marginal * {
|
||||
@apply min-h-0 min-w-0 overflow-ellipsis overflow-hidden
|
||||
}
|
||||
|
||||
.ha-tradzhtext .ha-btn-collapsed-box,
|
||||
.ha-lettertext .ha-btn-collapsed-box {
|
||||
@apply absolute left-full ml-4 hidden md:block cursor-pointer leading-none mt-0.5
|
||||
@@ -957,46 +969,40 @@
|
||||
}
|
||||
|
||||
.ha-aq,
|
||||
.ha-aq * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-aq *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply font-sans
|
||||
}
|
||||
|
||||
.ha-ul,
|
||||
.ha-ul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-ul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply underline
|
||||
}
|
||||
|
||||
.ha-del,
|
||||
.ha-del * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal, .ha-diagdel) {
|
||||
.ha-del *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-diagdel, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply inline line-through
|
||||
}
|
||||
|
||||
.ha-hand,
|
||||
.ha-hand
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-hand *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply font-classy text-[0.9rem]
|
||||
}
|
||||
|
||||
.ha-added,
|
||||
.ha-added
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-added *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply px-1 rounded-sm
|
||||
}
|
||||
|
||||
.ha-note,
|
||||
.ha-note
|
||||
*
|
||||
:not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-note *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply italic
|
||||
}
|
||||
|
||||
.ha-emph {
|
||||
.ha-emph *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply italic
|
||||
}
|
||||
|
||||
.ha-sup {
|
||||
.ha-sup *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal, .ha-marginal *, .ha-btn-collapsed-box) {
|
||||
@apply relative -top-[0.3em] text-[80%]
|
||||
}
|
||||
|
||||
@@ -1010,17 +1016,17 @@
|
||||
}
|
||||
|
||||
.ha-ful,
|
||||
.ha-ful * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-ful *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
@apply inline border-b pb-[2px]
|
||||
}
|
||||
|
||||
.ha-dul,
|
||||
.ha-dul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-dul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
@apply underline decoration-double
|
||||
}
|
||||
|
||||
.ha-tul,
|
||||
.ha-tul * :not(.ha-linecount *, .ha-linecount, .ha-marginal *, .ha-marginal) {
|
||||
.ha-tul *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
@apply underline border-b-[3px] border-double
|
||||
}
|
||||
|
||||
@@ -1126,18 +1132,14 @@
|
||||
@apply hidden desktop:block absolute -top-[0.15rem] cursor-pointer
|
||||
}
|
||||
|
||||
.ha-collapsed-box {
|
||||
@apply z-0 overflow-hidden overflow-ellipsis cursor-default
|
||||
.ha-collapsed-box,
|
||||
.ha-collapsed-box * {
|
||||
@apply z-0 overflow-hidden min-w-0 min-h-0 overflow-ellipsis cursor-default
|
||||
}
|
||||
|
||||
.ha-expanded-box {
|
||||
@apply pb-1 z-[1000] !h-auto !max-h-screen
|
||||
}
|
||||
|
||||
/* .ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-collapsed-box:hover,
|
||||
.ha-register .ha-forschung .ha-register-body .ha-commenthead .ha-collapsed-box:hover {
|
||||
@apply shadow-md z-[1000] !h-auto
|
||||
} */
|
||||
}
|
||||
|
||||
.ha-lettertext .ha-marginalbox:before {
|
||||
@@ -1197,6 +1199,12 @@ body {
|
||||
list-style-type:circle;
|
||||
} */
|
||||
|
||||
.ha-tradzhtext .ha-marginalbox.ha-collapsed-box .ha-marginallist .ha-marginal,
|
||||
.ha-lettertext .ha-marginalbox.ha-collapsed-box .ha-marginallist .ha-marginal {
|
||||
display: -webkit-inline-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.ha-diagdel {
|
||||
text-decoration: none !important;
|
||||
text-decoration-line: none !important;
|
||||
@@ -1222,7 +1230,7 @@ body {
|
||||
}
|
||||
|
||||
.ha-del .ha-del,
|
||||
.ha-del .ha-del * {
|
||||
.ha-del .ha-del *:not(.ha-linecount *, .ha-linecount, .ha-marginalbox *, .ha-marginalbox, .ha-marginal *, .ha-marginal, .ha-btn-collapsed-box) {
|
||||
-moz-text-decoration-style: double;
|
||||
-webkit-text-decoration-style: double !important;
|
||||
text-decoration-thickness: 1px;
|
||||
|
||||
@@ -54,7 +54,7 @@ const getLineHeight = function (element) {
|
||||
return ret;
|
||||
};
|
||||
|
||||
const collapsebox = function (element, height) {
|
||||
const collapsebox = function (element, height, lineheight) {
|
||||
element.style.maxHeight = height + "px";
|
||||
element.classList.add("ha-collapsed-box");
|
||||
element.classList.remove("ha-expanded-box");
|
||||
@@ -135,14 +135,38 @@ const overlappingcollapsebox = function (selector, hoverfunction) {
|
||||
if (i < boxes.length - 1) {
|
||||
let element = boxes[i];
|
||||
let thisrect = element.getBoundingClientRect();
|
||||
let nextrect = boxes[i+1].getBoundingClientRect();
|
||||
let nextrect = boxes[i + 1].getBoundingClientRect();
|
||||
let overlap = thisrect.bottom - nextrect.top;
|
||||
if (overlap >= 0 && !(window.getComputedStyle(element).display === "none")) {
|
||||
if (
|
||||
overlap >= 0 &&
|
||||
!(window.getComputedStyle(element).display === "none")
|
||||
) {
|
||||
let newlength = thisrect.height - overlap;
|
||||
let remainder = newlength % lineheight;
|
||||
newlength = newlength - remainder - 1;
|
||||
requestAnimationFrame(() => { collapsebox(element, newlength) });
|
||||
requestAnimationFrame(() => { addbuttoncaollapsebox(element, newlength, hoverfunction) });
|
||||
|
||||
// Line clamping for Marginals
|
||||
if (element.classList.contains("ha-marginalbox")) {
|
||||
let marginals = element.querySelectorAll(".ha-marginal");
|
||||
let h = 0;
|
||||
for (let m of marginals) {
|
||||
let cr = m.getBoundingClientRect();
|
||||
let eh = cr.bottom - cr.top;
|
||||
h += eh;
|
||||
if (h >= newlength) {
|
||||
let lines = Math.floor(eh / lineheight);
|
||||
let cutoff = Math.floor((h-newlength) / lineheight);
|
||||
m.style.cssText += "-webkit-line-clamp: " + (lines-cutoff) + ";";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
collapsebox(element, newlength, lineheight);
|
||||
});
|
||||
requestAnimationFrame(() => {
|
||||
addbuttoncaollapsebox(element, newlength, hoverfunction);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,52 +200,57 @@ const showhidebutton = function (
|
||||
|
||||
for (let element of divlist) {
|
||||
let hiddenelement = document.getElementById(element);
|
||||
if (hiddenelement !== null) hiddenelement.classList.add("hide");
|
||||
if (hiddenelement !== null) {
|
||||
hiddenelement.classList.add("hide")
|
||||
hiddenelement.classList.remove("flow-root");
|
||||
};
|
||||
}
|
||||
|
||||
if (button !== null) button.classList.add("active");
|
||||
if (div !== null) div.classList.remove("hide");
|
||||
if (div !== null) {
|
||||
div.classList.add("flow-root");
|
||||
div.classList.remove("hide");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Functions for switching theme
|
||||
const go_to_dark = function() {
|
||||
localStorage.setItem('theme', 'ha-toggledark');
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
const go_to_dark = function () {
|
||||
localStorage.setItem("theme", "ha-toggledark");
|
||||
document.documentElement.classList.add("dark");
|
||||
};
|
||||
|
||||
const go_to_twilight = function() {
|
||||
document.documentElement.classList.remove('dark')
|
||||
const go_to_twilight = function () {
|
||||
document.documentElement.classList.remove("dark");
|
||||
let elements = document.getElementsByClassName("ha-twilighttogglebar");
|
||||
for (let el of elements) {
|
||||
el.classList.add("dark");
|
||||
}
|
||||
localStorage.setItem('theme', 'ha-toggletwilight');
|
||||
}
|
||||
localStorage.setItem("theme", "ha-toggletwilight");
|
||||
};
|
||||
|
||||
const go_to_bright = function() {
|
||||
document.documentElement.classList.remove('dark');
|
||||
const go_to_bright = function () {
|
||||
document.documentElement.classList.remove("dark");
|
||||
let elements = document.getElementsByClassName("ha-twilighttogglebar");
|
||||
for (let el of elements) {
|
||||
el.classList.remove("dark");
|
||||
}
|
||||
localStorage.setItem('theme', 'ha-togglebright');
|
||||
}
|
||||
localStorage.setItem("theme", "ha-togglebright");
|
||||
};
|
||||
|
||||
// Functions for reading theme settings
|
||||
const get_theme_settings = function(standard) {
|
||||
var theme = localStorage.getItem('theme');
|
||||
const get_theme_settings = function (standard) {
|
||||
var theme = localStorage.getItem("theme");
|
||||
if (theme === null) theme = standard;
|
||||
let toggleSwitch = document.getElementById(theme).click();
|
||||
}
|
||||
};
|
||||
|
||||
const collapseboxes = function() {
|
||||
const collapseboxes = function () {
|
||||
overlappingcollapsebox(".ha-neuzeit .ha-letlinks", true);
|
||||
overlappingcollapsebox(".ha-forschung .ha-letlinks", true);
|
||||
overlappingcollapsebox(".ha-lettertext .ha-marginalbox", true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////// ONLOAD ////////////////////////////////////
|
||||
window.addEventListener("load", function () {
|
||||
@@ -247,24 +276,59 @@ window.addEventListener("load", function () {
|
||||
// Letter / Register View: Collapse all unfit boxes + resize observer
|
||||
collapseboxes();
|
||||
var doit;
|
||||
this.window.addEventListener('resize', function() {
|
||||
this.window.addEventListener("resize", function () {
|
||||
this.clearTimeout(doit);
|
||||
this.setTimeout(collapseboxes, 250);
|
||||
});
|
||||
|
||||
|
||||
// Letter View: Show / Hide Tabs
|
||||
let buttonlist = ["ha-lettertextbtn", "ha-additionsbtn", "ha-marginalsbtn"];
|
||||
let divlist = ["ha-lettertext", "ha-additions", "ha-marginals"];
|
||||
|
||||
if (this.document.getElementById("ha-lettertextbtn") !== null) {
|
||||
showhidebutton("ha-lettertextbtn", "ha-lettertext", buttonlist, divlist, false);
|
||||
showhidebutton("ha-additionsbtn", "ha-additions", buttonlist, divlist, true);
|
||||
showhidebutton("ha-marginalsbtn", "ha-marginals", buttonlist, divlist, true);
|
||||
showhidebutton(
|
||||
"ha-lettertextbtn",
|
||||
"ha-lettertext",
|
||||
buttonlist,
|
||||
divlist,
|
||||
false
|
||||
);
|
||||
showhidebutton(
|
||||
"ha-additionsbtn",
|
||||
"ha-additions",
|
||||
buttonlist,
|
||||
divlist,
|
||||
true
|
||||
);
|
||||
showhidebutton(
|
||||
"ha-marginalsbtn",
|
||||
"ha-marginals",
|
||||
buttonlist,
|
||||
divlist,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
showhidebutton("ha-lettertextbtn", "ha-lettertext", buttonlist, divlist, true);
|
||||
showhidebutton("ha-additionsbtn", "ha-additions", buttonlist, divlist, false);
|
||||
showhidebutton("ha-marginalsbtn", "ha-marginals", buttonlist, divlist, true);
|
||||
showhidebutton(
|
||||
"ha-lettertextbtn",
|
||||
"ha-lettertext",
|
||||
buttonlist,
|
||||
divlist,
|
||||
true
|
||||
);
|
||||
showhidebutton(
|
||||
"ha-additionsbtn",
|
||||
"ha-additions",
|
||||
buttonlist,
|
||||
divlist,
|
||||
false
|
||||
);
|
||||
showhidebutton(
|
||||
"ha-marginalsbtn",
|
||||
"ha-marginals",
|
||||
buttonlist,
|
||||
divlist,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// Theme: Get saved theme from memory and check the box accordingly
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<opus>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<opus>
|
||||
<data>
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<opus>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<opus>
|
||||
<data>
|
||||
<kommentare>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<opus>
|
||||
<data>
|
||||
<kommentare>
|
||||
|
||||
Reference in New Issue
Block a user