Merge branch 'main' of github.com:schnulller/hamann-ausgabe-core

This commit is contained in:
schnulller
2022-06-09 12:38:12 +02:00
28 changed files with 2500 additions and 4757 deletions

View File

@@ -21,6 +21,7 @@ namespace HaDocument
private static ILibrary _library; private static ILibrary _library;
public static ILibrary Create(IHaDocumentOptions Settings) { public static ILibrary Create(IHaDocumentOptions Settings) {
_lib = new IntermediateLibrary();
SettingsValidator.Validate(Settings); SettingsValidator.Validate(Settings);
_settings = Settings; _settings = Settings;
_createReader(); _createReader();

View File

@@ -166,11 +166,18 @@ public class APIController : Controller {
if (!ModelState.IsValid || element == null) if (!ModelState.IsValid || element == null)
return BadRequest(ModelState); return BadRequest(ModelState);
var savedfile = await _xmlProvider.SaveHamannFile(element, _targetFilePath, ModelState); var savedfile = await _xmlProvider.SaveHamannFile(element, _targetFilePath, ModelState);
if (!ModelState.IsValid || savedfile == null) if (!ModelState.IsValid || savedfile == null) {
if (savedfile != null)
_xmlProvider.DeleteHamannFile(savedfile.Name);
return BadRequest(ModelState); return BadRequest(ModelState);
}
_ = _lib.SetLibrary(savedfile.PhysicalPath, ModelState); _ = _lib.SetLibrary(savedfile.PhysicalPath, ModelState);
if (!ModelState.IsValid) if (!ModelState.IsValid) {
_xmlProvider.DeleteHamannFile(savedfile.Name);
return BadRequest(ModelState); return BadRequest(ModelState);
}
_xmlProvider.SetInProduction(savedfile);
_xmlService.SetInProduction();
return Created("/", _xmlProvider.GetHamannFiles()); return Created("/", _xmlProvider.GetHamannFiles());
} }
@@ -300,9 +307,6 @@ public class APIController : Controller {
continue; continue;
} }
filename = XMLFileHelpers.StreamToString(section.Body, ModelState);
if (!ModelState.IsValid) return BadRequest(ModelState);
if (hasContentDispositionHeader && contentDisposition != null) { if (hasContentDispositionHeader && contentDisposition != null) {
if (!MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { if (!MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) {
ModelState.AddModelError("Error", $"Wrong Content-Dispostion Headers in Multipart Document"); ModelState.AddModelError("Error", $"Wrong Content-Dispostion Headers in Multipart Document");
@@ -310,7 +314,7 @@ public class APIController : Controller {
} }
filename = XMLFileHelpers.StreamToString(section.Body, ModelState); filename = XMLFileHelpers.StreamToString(section.Body, ModelState);
if (!ModelState.IsValid) return BadRequest(ModelState);
} }
try { try {
@@ -332,17 +336,12 @@ public class APIController : Controller {
return BadRequest(ModelState); return BadRequest(ModelState);
} }
try { _ = _lib.SetLibrary(newFile.First().PhysicalPath, ModelState);
_ = _lib.SetLibrary(newFile.First().PhysicalPath, ModelState); if (!ModelState.IsValid) return BadRequest(ModelState);
}
catch (Exception ex) {
ModelState.AddModelError("Error", "Error parsing the file: " + ex.Message);
return BadRequest(ModelState);
}
_xmlProvider.SetInProduction(newFile.First()); _xmlProvider.SetInProduction(newFile.First());
_xmlService.UnUseProduction(); _xmlService.UnUseProduction();
return Created("/", null); return Created("/", newFile.First());
} }
} }

View File

@@ -61,7 +61,7 @@ public class RegisterController : Controller {
} }
// Model instantiation // Model instantiation
var model = new RegisterViewModel(category, id, res, title) { var model = new RegisterViewModel(category, id, res, title, false) {
AvailableCategories = availableCategories, AvailableCategories = availableCategories,
}; };
@@ -104,7 +104,7 @@ public class RegisterController : Controller {
} }
// Model instantiation // Model instantiation
var model = new RegisterViewModel(category, id, res, title) { var model = new RegisterViewModel(category, id, res, title, false) {
AvailableCategories = availableCategories, AvailableCategories = availableCategories,
}; };
@@ -154,7 +154,7 @@ public class RegisterController : Controller {
} }
// Model instantiation // Model instantiation
var model = new RegisterViewModel(category, id, res, title) { var model = new RegisterViewModel(category, id, res, title, true) {
AvailableCategories = availableCategories, AvailableCategories = availableCategories,
AvailableSideCategories = AvailableSideCategories AvailableSideCategories = AvailableSideCategories
}; };

View File

@@ -35,8 +35,7 @@ public class HaDocumentWrapper : IHaDocumentWrappper {
Library = HaDocument.Document.Create(new HaWeb.Settings.HaDocumentOptions() { HamannXMLFilePath = filepath, AvailableYearRange = (_startYear, _endYear) }); Library = HaDocument.Document.Create(new HaWeb.Settings.HaDocumentOptions() { HamannXMLFilePath = filepath, AvailableYearRange = (_startYear, _endYear) });
} }
catch (Exception ex) { catch (Exception ex) {
if (ModelState != null) ModelState.AddModelError("Error:", "Das Dokument konnte nicht geparst werden: " + ex.Message); if (ModelState != null) ModelState.AddModelError("Error", "Das Dokument konnte nicht geparst werden: " + ex.Message);
Console.WriteLine(ex.Message);
return null; return null;
} }
return Library; return Library;

View File

@@ -12,4 +12,5 @@ public interface IXMLProvider {
public List<IFileInfo>? GetHamannFiles(); public List<IFileInfo>? GetHamannFiles();
public IFileInfo? GetInProduction(); public IFileInfo? GetInProduction();
public void SetInProduction(IFileInfo info); public void SetInProduction(IFileInfo info);
public void DeleteHamannFile(string filename);
} }

View File

@@ -10,7 +10,7 @@ public class XMLProvider : IXMLProvider {
private Dictionary<string, FileList?>? _Files; private Dictionary<string, FileList?>? _Files;
private Dictionary<string, IXMLRoot>? _Roots; private Dictionary<string, IXMLRoot>? _Roots;
private List<IFileInfo>? _HamannFiles; private List<IFileInfo>? _HamannFiles;
private IFileInfo? _InProduction; private Stack<IFileInfo>? _InProduction;
public XMLProvider(IFileProvider provider, IXMLService xmlservice) { public XMLProvider(IFileProvider provider, IXMLService xmlservice) {
_fileProvider = provider; _fileProvider = provider;
@@ -26,9 +26,24 @@ public class XMLProvider : IXMLProvider {
public List<IFileInfo>? GetHamannFiles() => this._HamannFiles; public List<IFileInfo>? GetHamannFiles() => this._HamannFiles;
public IFileInfo? GetInProduction() => this._InProduction; public IFileInfo? GetInProduction() {
if (_InProduction == null || !_InProduction.Any()) return null;
return this._InProduction.Peek();
}
public void SetInProduction(IFileInfo info) => _InProduction = info; public void DeleteHamannFile(string filename) {
if (_HamannFiles == null) return;
var files = _HamannFiles.Where(x => x.Name == filename);
foreach (var file in files) {
File.Delete(file.PhysicalPath);
}
_HamannFiles.RemoveAll(x => x.Name == filename);
}
public void SetInProduction(IFileInfo info) {
if (_InProduction == null) _InProduction = new Stack<IFileInfo>();
_InProduction.Push(info);
}
public FileList? GetFiles(string prefix) public FileList? GetFiles(string prefix)
=> _Files != null && _Files.ContainsKey(prefix) ? _Files[prefix] : null; => _Files != null && _Files.ContainsKey(prefix) ? _Files[prefix] : null;
@@ -65,7 +80,7 @@ public class XMLProvider : IXMLProvider {
public async Task<IFileInfo?> SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary ModelState) { public async Task<IFileInfo?> SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary ModelState) {
var date = DateTime.Now; var date = DateTime.Now;
var filename = "hamann_" + date.Year + "-" + date.Month + "-" + date.Day + ".xml"; var filename = "hamann_" + date.Year + "-" + date.Month + "-" + date.Day + "." + Path.GetRandomFileName() + ".xml";
var directory = Path.Combine(basefilepath, "hamann"); var directory = Path.Combine(basefilepath, "hamann");
var path = Path.Combine(directory, filename); var path = Path.Combine(directory, filename);
@@ -89,7 +104,6 @@ public class XMLProvider : IXMLProvider {
if (_HamannFiles == null) _HamannFiles = new List<IFileInfo>(); if (_HamannFiles == null) _HamannFiles = new List<IFileInfo>();
_HamannFiles.RemoveAll(x => x.Name == info.Name); _HamannFiles.RemoveAll(x => x.Name == info.Name);
_HamannFiles.Add(info); _HamannFiles.Add(info);
_InProduction = info;
return info; return info;
} }

View File

@@ -6,24 +6,16 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<!-- exclude all Content items from being watched --> <ItemGroup>
<Content Update="wwwroot/css/site.css" Watch="false" /> <Content Remove="wwwroot\css\site.css" />
<Content Include="wwwroot\css\site.css" Watch="false" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Watch Include="**\*.js" Exclude="node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
<Watch Include="**\*.css" Exclude="node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
<Watch Include="**\*.cs" Exclude="node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
<Watch Include="**\*.cshtml" Exclude="node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
<Watch Include="**\*.csproj" Exclude="node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckBuilt Include="postcss.config.js" Set="Css" />
<UpToDateCheckBuilt Include="tailwind.config.js" Set="Css" />
</ItemGroup>
<Target Name="Tailwind" BeforeTargets="Build"> <Target Name="Tailwind" BeforeTargets="Build">
<Exec Command="npm run css:build" /> <Exec Command="npm run css_build" />
</Target> </Target>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="2.5.1" /> <PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="2.5.1" />
</ItemGroup> </ItemGroup>
@@ -32,6 +24,4 @@
<ProjectReference Include="..\HaXMLReaderV6\HaXMLReaderV6.csproj" /> <ProjectReference Include="..\HaXMLReaderV6\HaXMLReaderV6.csproj" />
<ProjectReference Include="..\HaDocumentV6\HaDocumentV6.csproj" /> <ProjectReference Include="..\HaDocumentV6\HaDocumentV6.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -17,7 +17,9 @@ public class FileList {
throw new Exception("Diese Liste kann nur Elemente des Typs " + XMLRoot.Prefix + " enthalten"); throw new Exception("Diese Liste kann nur Elemente des Typs " + XMLRoot.Prefix + " enthalten");
if (_Files == null) _Files = new HashSet<XMLRootDocument>(); if (_Files == null) _Files = new HashSet<XMLRootDocument>();
if (!_Files.Contains(document)) _Files.Add(document); var replacing = _Files.Where(x => x.FileName == document.FileName);
if (replacing != null && replacing.Any()) _Files.Remove(replacing.First());
_Files.Add(document);
} }
public bool Contains(XMLRootDocument doc) { public bool Contains(XMLRootDocument doc) {

View File

@@ -5,6 +5,7 @@ public class RegisterViewModel {
public string Category { get; private set; } public string Category { get; private set; }
public string Id { get; private set; } public string Id { get; private set; }
public string Title { get; private set; } public string Title { get; private set; }
public bool AllowSendIn { get; private set; }
private List<(string, string)>? _AvailableCategories; private List<(string, string)>? _AvailableCategories;
private List<(string, string)>? _AvailableSideCategories; private List<(string, string)>? _AvailableSideCategories;
@@ -41,10 +42,11 @@ public class RegisterViewModel {
} }
} }
public RegisterViewModel(string category, string id, List<CommentModel> parsedComments, string title) { public RegisterViewModel(string category, string id, List<CommentModel> parsedComments, string title, bool allowSendIn) {
this.Category = HttpUtility.HtmlAttributeEncode(category); this.Category = HttpUtility.HtmlAttributeEncode(category);
this.Id = HttpUtility.HtmlAttributeEncode(id); this.Id = HttpUtility.HtmlAttributeEncode(id);
this.ParsedComments = parsedComments; this.ParsedComments = parsedComments;
this.Title = HttpUtility.HtmlEncode(title); this.Title = HttpUtility.HtmlEncode(title);
this.AllowSendIn = allowSendIn;
} }
} }

View File

@@ -33,8 +33,6 @@ Startseite für die Briefausgebe / Werkausgabe. Unterschiedliche Menüs für die
Briefe beim Namen Briefe beim Namen
- GND Normdaten der Namen
TODO 1127 zu breit TODO 1127 zu breit
TODO tabellen ok, ausser 939, 806 falsch geschachtelt: dort sind htabs geschachtelt TODO tabellen ok, ausser 939, 806 falsch geschachtelt: dort sind htabs geschachtelt
TODO 659 align center und align-right ueberschneidugn TODO 659 align center und align-right ueberschneidugn
@@ -43,6 +41,4 @@ TODO pills are not mobile friendly (hover / click)
TODO Evtl alignment von center / right an der letzten oder nächsten zeile TODO Evtl alignment von center / right an der letzten oder nächsten zeile
TODO Abhärten des Konstruktors von XMLRootDokument für von außerhalb platzierte Dokumente TODO Abhärten des Konstruktors von XMLRootDokument für von außerhalb platzierte Dokumente
TODO XML-Check im Client TODO XML-Check im Client
TODO Lock für die Liste, Bzw ConcurretBag TODO Lock für die Liste, Bzw ConcurretBag
TODO Up-Button
TODO Neue Forschungsliteratur einsenden

View File

@@ -25,83 +25,72 @@
} }
<div class="ha-uploadpublishforms"> <div class="ha-uploadpublishforms">
<form class="ha-uploadform" id="uploadForm" asp-controller="API" asp-action="Upload" method="post" enctype="multipart/form-data"> @await Html.PartialAsync("/Views/Shared/_UploadForm.cshtml", Model)
<label class="ha-uploadfilelabel" id="dropzone">
<input class="hidden" id="file" type="file" accept=".xml" name="file" />
<div class="ha-uploadtext">Upload</div>
<div class="ha-lds-ellipsis" id="ha-lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</label>
<div class="ha-uploadmessage" id="ha-uploadmessage">
Fehler!<br/>
<output form="uploadForm" name="upload-result"></output>
</div>
</form>
<form class="ha-publishform" id="ha-publishform" asp-controller="API" asp-action="LocalPublish" method="post" enctype="multipart/form-data"> <a class="ha-publishbutton" asp-controller="Upload" asp-action="Index" asp-route-id="@string.Empty">
<label class="ha-publishfilelabel" id="ha-publishfilelabel"> <div class="ha-publishtext">Veröffentlichen</div>
<div class="ha-publishtext">Veröffentlichen</div> </a>
<div class="ha-lds-ellipsis" id="ha-lds-ellipsis-publish"><div></div><div></div><div></div><div></div></div>
</label>
<div class="ha-publishmessage" id="ha-publishmessage">
@* Fehler!<br/> *@
<output form="uploadForm" name="publish-result" id="publish-result"></output>
</div>
</form>
</div> </div>
</div> </div>
<div class="ha-uploadheader"> <div class="ha-uploadheader">
<h1 class="ha-uploadtitle">@Model.ActiveTitle</h1> <h1 class="ha-uploadtitle">@Model.ActiveTitle</h1>
</div> </div>
<div class="ha-uploadcontainer"> <div class="ha-uploadcontainer">
@* File Category Page File List *@ @* File Category Page File List *@
@if (Model.AvailableFiles != null && Model.AvailableFiles.Any()) { @if (Model.AvailableFiles != null && Model.AvailableFiles.Any()) {
<div class="ha-filesheader"> <div class="ha-filesheader">
<div class="ha-availablefiles" id="ha-availablefiles"> <div class="ha-availablefiles" id="ha-availablefiles">
<div class="ha-availablefilestitle">Datei(en)</div> <div class="ha-availablefilestitle">Datei(en)</div>
@if(Model.UsedFiles != null && Model.UsedFiles.ContainsKey(Model.Prefix)) { @if(Model.UsedFiles != null && Model.UsedFiles.ContainsKey(Model.Prefix)) {
<div class="ha-usedfilelist"> <div class="ha-usedfilelist">
@foreach (var item in Model.UsedFiles[Model.Prefix]!) @foreach (var item in Model.UsedFiles[Model.Prefix]!)
{ {
if(item == Model.UsedFiles[Model.Prefix]!.Last()) { if(item == Model.UsedFiles[Model.Prefix]!.Last()) {
<span class="ha-usedfile">@item.FileName</span> <span class="ha-usedfile">@item.FileName</span>
} }
else { else {
<span class="ha-usedfile">@item.FileName,</span> <span class="ha-usedfile">@item.FileName,</span>
}
} }
</div>
} }
</div> </div>
} <div class="ha-availablefileslist hidden" id="ha-availablefileslist">
@await Html.PartialAsync("/Views/Shared/_FileListForm.cshtml", (Model.AvailableFiles, "Verfügbare Dateien", "API", "SetUsed", Model.Prefix, "/Download/XML/" + Model.Prefix + "/", true))
</div>
</div> </div>
<div class="ha-availablefileslist hidden" id="ha-availablefileslist">
@await Html.PartialAsync("/Views/Shared/_FileList.cshtml", (Model.AvailableFiles, "Verfügbare Dateien:", "API", "SetUsed", Model.Prefix, "/Download/XML/" + Model.Prefix + "/", true))
</div>
</div>
}
@* Start Page File List *@
else {
<div class="ha-hamannfilechooser">
@await Html.PartialAsync("/Views/Shared/_FileList.cshtml", (Model.HamannFiles, "Verfügbare Hamann-Dateien", "API", "SetUsedHamann", string.Empty, "/Download/XML/", false))
</div>
}
@* File Category Page Syntax Check *@
@if (Model.UsedFiles != null && Model.Prefix != null && Model.UsedFiles.ContainsKey(Model.Prefix)) {
<div class="ha-errorswarnings">
<div class="ha-criticalerrors">
</div>
<div class="ha-warnings">
</div>
</div>
<div class="ha-crossfilechecking">
</div> @if (Model.UsedFiles != null && Model.Prefix != null && Model.UsedFiles.ContainsKey(Model.Prefix)) {
} <div class="ha-errorswarnings">
<div class="ha-criticalerrors">
</div>
<div class="ha-warnings">
</div>
</div>
<div class="ha-crossfilechecking">
</div>
}
}
@* Start Page File List *@
else {
<div class="ha-publishfilelist">
@await Html.PartialAsync("/Views/Shared/_PublishForm.cshtml", Model)
</div>
<div class="ha-hamannfilechooser">
@await Html.PartialAsync("/Views/Shared/_FileListForm.cshtml", (Model.HamannFiles, "Verfügbare Hamann-Dateien", "API", "SetUsedHamann", string.Empty, "/Download/XML/", false))
</div>
}
</div> </div>
@@ -110,7 +99,6 @@ else {
"use strict"; "use strict";
const hideshowfiles = function() { const hideshowfiles = function() {
let elem = document.getElementById("ha-availablefileslist"); let elem = document.getElementById("ha-availablefileslist");
console.log("hello!");
if (elem.classList.contains('hidden')) { if (elem.classList.contains('hidden')) {
elem.classList.remove('hidden'); elem.classList.remove('hidden');
@@ -122,104 +110,6 @@ else {
} }
} }
const dropHandler = function (formelement, ev, dropzone) {
ev.preventDefault();
if (ev.dataTransfer.items) {
if (ev.dataTransfer.items[0].kind === 'file') {
var file = ev.dataTransfer.items[0].getAsFile();
UPLOADSubmit(formelement, file);
} else {
var file = ev.dataTransfer.files[0];
UPLOADSubmit(formelement, file);
}
}
}
const dragOverHandler = function (ev, dropzone) {
ev.preventDefault();
}
const dragLeaveHander = function (ev, dropzone) {
ev.preventDefault();
}
const dragEnterHandler = function (ev, dropzone) {
ev.preventDefault();
}
const LOCALPUBLISHSubmit = async function (oFormElement) {
var fd = new FormData();
document.getElementById("ha-publishfilelabel").style.pointerEvents = "none";
document.getElementById("ha-lds-ellipsis-publish").style.display = "inline-block";
document.getElementById("ha-publishmessage").style.opacity = "0";
await fetch(oFormElement.action, {
method: 'POST',
headers: {
'RequestVerificationToken': getCookie('RequestVerificationToken')
}
})
.then(response => response.json())
.then(json => {
if ("Error" in json) {
document.getElementById("ha-publishfilelabel").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-publish").style.display = "none";
document.getElementById("ha-publishmessage").style.opacity = "1";
document.getElementById("publish-result").value = json.Error;
} else {
document.getElementById("ha-publishfilelabel").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-publish").style.display = "none";
document.getElementById("ha-publishmessage").style.opacity = "1";
document.getElementById("publish-result").value = "Erfolg!";
window.location.replace("/Admin/Upload/");
}
})
.catch ((e) => {
document.getElementById("ha-publishfilelabel").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-publish").style.display = "none";
document.getElementById("publish-result").value = "Keine Antwort. Bitte Seite neu laden!";
})
}
const UPLOADSubmit = async function (oFormElement, file = null) {
var fd = new FormData();
if (file !== null) fd.append("file", file);
else fd = new FormData(oFormElement);
document.getElementById("dropzone").style.pointerEvents = "none";
document.getElementById("ha-lds-ellipsis").style.display = "inline-block";
document.getElementById("ha-uploadmessage").style.opacity = "0";
await fetch(oFormElement.action, {
method: 'POST',
headers: {
'RequestVerificationToken': getCookie('RequestVerificationToken')
},
body: fd
})
.then(response => response.json())
.then(json => {
if ("Error" in json) {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis").style.display = "none";
document.getElementById("ha-uploadmessage").style.opacity = "1";
oFormElement.elements.namedItem("upload-result").value = json.Error;
} else {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis").style.display = "none";
oFormElement.elements.namedItem("upload-result").value = "Erfolg!";
if ("Prefix" in json[0]) {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis").style.display = "none";
window.location.replace("/Admin/Upload/" + json[0].Prefix);
}
}
})
.catch ((e) => {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis").style.display = "none";
document.getElementById("ha-uploadmessage").style.opacity = "1";
oFormElement.elements.namedItem("upload-result").value = "Keine Antwort. Bitte Seite neu laden!";
})
}
function getCookie(name) { function getCookie(name) {
var value = "; " + document.cookie; var value = "; " + document.cookie;
var parts = value.split("; " + name + "="); var parts = value.split("; " + name + "=");
@@ -227,20 +117,9 @@ else {
} }
window.addEventListener("load", function () { window.addEventListener("load", function () {
var submitelement = document.getElementById("file");
var formelement = document.getElementById("uploadForm");
var dropzone = document.getElementById("dropzone");
var publishelement = document.getElementById("ha-publishform");
var publishbutton = document.getElementById("ha-publishfilelabel");
var filesbutton = document.getElementById("ha-availablefiles"); var filesbutton = document.getElementById("ha-availablefiles");
if (filesbutton !== null) if (filesbutton !== null)
filesbutton.addEventListener("click", () => hideshowfiles()); filesbutton.addEventListener("click", () => hideshowfiles());
publishbutton.addEventListener("click", () => LOCALPUBLISHSubmit(publishelement));
submitelement.addEventListener("change", () => UPLOADSubmit(formelement));
dropzone.addEventListener("drop", (ev) => dropHandler(formelement, ev, dropzone));
dropzone.addEventListener("dragover", (ev) => dragOverHandler(ev, dropzone));
dropzone.addEventListener("dragleave", (ev) => dragLeaveHander(ev, dropzone));
dropzone.addEventListener("dragenter", (ev) => dragEnterHandler(ev, dropzone));
}); });

View File

@@ -51,20 +51,11 @@
<div class="ha-letterbody " id="ha-letterbody"> <div class="ha-letterbody " id="ha-letterbody">
<div class="ha-lettertext @minwidth" id="ha-lettertext"> <div class="ha-lettertext @minwidth" id="ha-lettertext">
@if (Model.MetaData.ParsedZHString != null) {
<div class="ha-linecount ha-firstline"> <div class="ha-linecount ha-firstline">
@if (Model.MetaData.ParsedZHString != null) <span>@Html.Raw(Model.MetaData.ParsedZHString)</span>
{
<span>@Html.Raw(Model.MetaData.ParsedZHString)</span>
}
else
{
<div class="ha-tooltip">
<div class="ha-pill">
<span>Neu</span>
</div>
</div>
}
</div> </div>
}
@Html.Raw(@Model.ParsedText) @Html.Raw(@Model.ParsedText)
@* It's not beautiful but it's a hack to keep the last comment within parent element boundaries: *@ @* It's not beautiful but it's a hack to keep the last comment within parent element boundaries: *@
<br> <br>

View File

@@ -36,7 +36,12 @@
<td>Durchstreichung</td> <td>Durchstreichung</td>
<td>in spitzen Klammern ⟨...⟩</td> <td>in spitzen Klammern ⟨...⟩</td>
<td><span class="ha-del">Durchstreichung</span> (einfache bis doppelte)</td> <td><span class="ha-del">Durchstreichung</span> (einfache bis doppelte)</td>
</tr> </tr>
<tr>
<td>Einfügung</td>
<td></td>
<td>&#x2E02;Einfügung&#x2E03; (lediglich in Einzelfällen)</td>
</tr>
<tr> <tr>
<td>Nicht entzifferbare Stelle / Unsichere Lesung</td> <td>Nicht entzifferbare Stelle / Unsichere Lesung</td>
<td>unterschiedlich gehandhabt</td> <td>unterschiedlich gehandhabt</td>

View File

@@ -28,6 +28,14 @@
<div class="@commentClass"> <div class="@commentClass">
<div class="ha-register-head"> <div class="ha-register-head">
<h1>@Model.Title</h1> <h1>@Model.Title</h1>
@if (Model.AllowSendIn) {
<div class="ha-register-add">
<a href="mailto:post@hamann-ausgabe.de?subject=Publikation%28en%29%20beitragen">
<div class="ha-register-add-plusbutton">+</div>
<div class="ha-register-add-text">Publikation(en) beitragen</div>
</a>
</div>
}
<div class="ha-register-nav" id="ha-register-nav"> <div class="ha-register-nav" id="ha-register-nav">
<div class="ha-register-left-nav"> <div class="ha-register-left-nav">
@if (Model.AvailableCategories != null) { @if (Model.AvailableCategories != null) {
@@ -60,15 +68,3 @@
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript">
(function() {
var ga = document.createElement('script');
ga.src = 'https://www.bibleserver.com/api/parser.js?key=262ea61e694b0d300608a52ef3f4585a10b47ff4&lang=de';
ga.setAttribute('async', 'true');
document.documentElement.firstChild.appendChild(ga);
})();
var bsQuery = '.ha-lemma'; // CSS-Selektor für Wrapper der Suche (optional)
var bsTrl = 'LUT'; // Verlinkte Übersetzung (optional)
</script>

View File

@@ -37,17 +37,23 @@
</div> </div>
} }
</div> </div>
<input class="btn ha-filelistbutton" type="submit" value="Laden" /> <output id ="ha-filelistoutput"></output>
<button type="submit" class="ha-filelistbutton" id="ha-filelistbutton" >
Laden
<div class="ha-lds-ellipsis-load" id="ha-lds-ellipsis-load"><div></div><div></div><div></div><div></div></div>
</button>
</form> </form>
} }
else { else {
<div>Keine Hamann-Dateien gefunden! Es wird eine fallback-Datei verwendet!</div> <div>Keine Dateien gefunden! Es wird eine fallback-Datei verwendet!</div>
} }
</fieldset> </fieldset>
<script> <script>
const USESubmit = async function (oFormElement, file = null) { const USESubmit = async function (oFormElement, file = null) {
let fd = new FormData(oFormElement); let fd = new FormData(oFormElement);
document.getElementById("ha-filelistbutton").style.pointerEvents = "none";
document.getElementById("ha-lds-ellipsis-load").style.display = "inline-block";
await fetch(oFormElement.action, { await fetch(oFormElement.action, {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -58,14 +64,20 @@
.then(response => response.json()) .then(response => response.json())
.then(json => { .then(json => {
if ("Error" in json) { if ("Error" in json) {
document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-load").style.display = "none";
document.getElementById("ha-filelistoutput").textContent = json.Error;
} }
else { else {
location.reload(); document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-load").style.display = "none";
location.reload();
} }
}) })
.catch ((e) => { .catch ((e) => {
location.reload(); document.getElementById("ha-filelistbutton").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-load").style.display = "none";
document.getElementById("ha-filelistoutput").textContent = e;
}) })
} }
</script> </script>

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="de" id="top">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
@@ -42,10 +42,17 @@
@await Html.PartialAsync("/Views/Shared/_Footer.cshtml") @await Html.PartialAsync("/Views/Shared/_Footer.cshtml")
</div> </div>
</div> </div>
<environment exclude="Development"> <environment exclude="Development">
@await Html.PartialAsync("/Views/Shared/_Javascript.cshtml") @await Html.PartialAsync("/Views/Shared/_Javascript.cshtml")
</environment> </environment>
<a class="ha-scrollbutton" id="ha-scrollbutton">
<svg class="ha-scrollbuttonarrow" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" stroke-width="2" d="M5 11l7-7 7 7M5 19l7-7 7 7" />
</svg>
</div>
@RenderSection("Scripts", required: false) @RenderSection("Scripts", required: false)
</body> </body>

View File

@@ -20,9 +20,9 @@
</div> </div>
</div> </div>
} }
else if (Model.ParsedZHString == null && Model.ShowZHData) { else if (Model.ParsedZHString == null) {
<div class="ha-tooltip"> <div class="ha-tooltip">
<div class="ha-pill"> <div class="ha-pill ha-newpill">
<span>Neu</span> <span>Neu</span>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,75 @@
@model UploadViewModel;
@if (Model.UsedFiles != null && Model.UsedFiles.Any()) {
<div class="ha-publishfilelisttitle">Aktuell geladene Dateien</div>
<table class="ha-publishfilelistlist">
@foreach (var (category, files) in Model.UsedFiles.OrderBy(x => x.Key))
{
<tr>
<td>@Model.AvailableRoots.Where(x => x.Prefix == category).First().Type:</td>
<td>
@foreach (var item in files)
{
if (item != files.Last()) {
<span>@item.FileName,</span>
}
else {
<span>@item.FileName</span>
}
}
</td>
</tr>
}
</table>
<form class="ha-publishform" id="ha-publishform" asp-controller="API" asp-action="LocalPublish" method="post" enctype="multipart/form-data">
<label class="ha-publishfilelabel" id="ha-publishfilelabel">
<div class="ha-publishtext">Dateien Veröffentlichen</div>
<div class="ha-lds-ellipsis-publish" id="ha-lds-ellipsis-publish"><div></div><div></div><div></div><div></div></div>
</label>
<div class="ha-publishmessage" id="ha-publishmessage">
<output form="uploadForm" name="publish-result" id="publish-result"></output>
</div>
</form>
}
<script>
const LOCALPUBLISHSubmit = async function (oFormElement) {
var fd = new FormData();
document.getElementById("ha-publishfilelabel").style.pointerEvents = "none";
document.getElementById("ha-lds-ellipsis-publish").style.display = "inline-block";
document.getElementById("ha-publishmessage").style.opacity = "0";
await fetch(oFormElement.action, {
method: 'POST',
headers: {
'RequestVerificationToken': getCookie('RequestVerificationToken')
}
})
.then(response => response.json())
.then(json => {
if ("Error" in json) {
document.getElementById("ha-publishfilelabel").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-publish").style.display = "none";
document.getElementById("ha-publishmessage").style.opacity = "1";
document.getElementById("publish-result").value = json.Error;
} else {
document.getElementById("ha-publishfilelabel").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-publish").style.display = "none";
document.getElementById("ha-publishmessage").style.opacity = "1";
document.getElementById("publish-result").value = "Erfolg!";
location.reload();
}
})
.catch ((e) => {
document.getElementById("ha-publishfilelabel").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-publish").style.display = "none";
document.getElementById("publish-result").value = "Keine Antwort. Bitte Seite neu laden!";
})
}
window.addEventListener("load", () => {
var publishelement = document.getElementById("ha-publishform");
var publishbutton = document.getElementById("ha-publishfilelabel");
publishbutton.addEventListener("click", () => LOCALPUBLISHSubmit(publishelement));
})
</script>

View File

@@ -0,0 +1,91 @@
@model UploadViewModel;
<form class="ha-uploadform" id="uploadForm" asp-controller="API" asp-action="Upload" method="post" enctype="multipart/form-data">
<label class="ha-uploadfilelabel" id="dropzone">
<input class="hidden" id="file" type="file" accept=".xml" name="file" />
<div class="ha-uploadtext">Upload</div>
<div class="ha-lds-ellipsis" id="ha-lds-ellipsis-upload"><div></div><div></div><div></div><div></div></div>
</label>
<div class="ha-uploadmessage" id="ha-uploadmessage">
Fehler!<br/>
<output form="uploadForm" name="upload-result"></output>
</div>
</form>
<script>
const dropHandler = function (formelement, ev, dropzone) {
ev.preventDefault();
if (ev.dataTransfer.items) {
if (ev.dataTransfer.items[0].kind === 'file') {
var file = ev.dataTransfer.items[0].getAsFile();
UPLOADSubmit(formelement, file);
} else {
var file = ev.dataTransfer.files[0];
UPLOADSubmit(formelement, file);
}
}
}
const dragOverHandler = function (ev, dropzone) {
ev.preventDefault();
}
const dragLeaveHander = function (ev, dropzone) {
ev.preventDefault();
}
const dragEnterHandler = function (ev, dropzone) {
ev.preventDefault();
}
const UPLOADSubmit = async function (oFormElement, file = null) {
var fd = new FormData();
if (file !== null) fd.append("file", file);
else fd = new FormData(oFormElement);
document.getElementById("dropzone").style.pointerEvents = "none";
document.getElementById("ha-lds-ellipsis-upload").style.display = "inline-block";
document.getElementById("ha-uploadmessage").style.opacity = "0";
await fetch(oFormElement.action, {
method: 'POST',
headers: {
'RequestVerificationToken': getCookie('RequestVerificationToken')
},
body: fd
})
.then(response => response.json())
.then(json => {
if ("Error" in json) {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-upload").style.display = "none";
document.getElementById("ha-uploadmessage").style.opacity = "1";
oFormElement.elements.namedItem("upload-result").value = json.Error;
} else {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-upload").style.display = "none";
oFormElement.elements.namedItem("upload-result").value = "Erfolg!";
if ("Prefix" in json[0]) {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-upload").style.display = "none";
window.location.replace("/Admin/Upload/" + json[0].Prefix);
}
}
})
.catch ((e) => {
document.getElementById("dropzone").style.pointerEvents = "auto";
document.getElementById("ha-lds-ellipsis-upload").style.display = "none";
document.getElementById("ha-uploadmessage").style.opacity = "1";
oFormElement.elements.namedItem("upload-result").value = "Keine Antwort. Bitte Seite neu laden!";
})
}
window.addEventListener("load", () => {
var submitelement = document.getElementById("file");
var formelement = document.getElementById("uploadForm");
var dropzone = document.getElementById("dropzone");
submitelement.addEventListener("change", () => UPLOADSubmit(formelement));
dropzone.addEventListener("drop", (ev) => dropHandler(formelement, ev, dropzone));
dropzone.addEventListener("dragover", (ev) => dragOverHandler(ev, dropzone));
dropzone.addEventListener("dragleave", (ev) => dragLeaveHander(ev, dropzone));
dropzone.addEventListener("dragenter", (ev) => dragEnterHandler(ev, dropzone));
});
</script>

View File

@@ -16,4 +16,5 @@ public interface IXMLService {
public Dictionary<string, FileList?>? GetInProduction(); public Dictionary<string, FileList?>? GetInProduction();
public void UnUse(string prefix); public void UnUse(string prefix);
public void UnUseProduction(); public void UnUseProduction();
public void SetInProduction();
} }

View File

@@ -7,7 +7,7 @@ public class XMLService : IXMLService {
private Dictionary<string, FileList?>? _Used; private Dictionary<string, FileList?>? _Used;
private Dictionary<string, IXMLRoot>? _Roots; private Dictionary<string, IXMLRoot>? _Roots;
private Dictionary<string, FileList?>? _InProduction; private Stack<Dictionary<string, FileList?>>? _InProduction;
public XMLService() { public XMLService() {
// Getting all classes which implement IXMLRoot for possible document endpoints // Getting all classes which implement IXMLRoot for possible document endpoints
@@ -32,7 +32,23 @@ public class XMLService : IXMLService {
public Dictionary<string, IXMLRoot>? GetRootsDictionary() => this._Roots == null ? null : this._Roots; public Dictionary<string, IXMLRoot>? GetRootsDictionary() => this._Roots == null ? null : this._Roots;
public Dictionary<string, FileList?>? GetInProduction() => this._InProduction; public Dictionary<string, FileList?>? GetInProduction() {
if (_InProduction == null) return null;
return this._InProduction.Peek();
}
public void SetInProduction() {
if (_Used == null) return;
var inProduction = new Dictionary<string, FileList?>();
foreach (var category in _Used) {
if (category.Value == null || category.Value.GetFileList() == null || !category.Value.GetFileList()!.Any())
return;
inProduction.Add(category.Key, category.Value);
}
if(_InProduction == null) _InProduction = new Stack<Dictionary<string, FileList?>>();
_InProduction.Push(inProduction);
}
public void UnUseProduction() => this._InProduction = null; public void UnUseProduction() => this._InProduction = null;
@@ -104,20 +120,19 @@ public class XMLService : IXMLService {
} }
var opus = new XElement("opus"); var opus = new XElement("opus");
var inProduction = new Dictionary<string, FileList?>(); // TODO: Workaround for bug in HaDocument: roots have to be added in a specific order
foreach (var category in _Used) { var used = _Used.OrderByDescending(x => x.Key);
foreach (var category in used) {
if (category.Value == null || category.Value.GetFileList() == null || !category.Value.GetFileList()!.Any()) { if (category.Value == null || category.Value.GetFileList() == null || !category.Value.GetFileList()!.Any()) {
ModelState.AddModelError("Error", _Roots![category.Key].Type + " nicht vorhanden."); ModelState.AddModelError("Error", _Roots![category.Key].Type + " nicht vorhanden.");
return null; return null;
} }
inProduction.Add(category.Key, category.Value);
var documents = category.Value.GetFileList(); var documents = category.Value.GetFileList();
foreach (var document in documents!) { foreach (var document in documents!) {
document.XMLRoot.MergeIntoFile(opus, document); document.XMLRoot.MergeIntoFile(opus, document);
} }
} }
_InProduction = inProduction;
return opus; return opus;
} }

1968
HaWeb/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,14 +4,23 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"css:build": "npx tailwind build ./wwwroot/css/site.css -o ./wwwroot/css/output.css" "css_build": "npx postcss wwwroot/css/site.css -o wwwroot/css/output.css",
"watch": "watch 'npm run css_build'"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",
"postcss": "^8.4.13", "cssnano": "^5.1.11",
"postcss": "^8.4.14",
"postcss-cli": "^9.1.0",
"tailwindcss": "^3.0.24" "tailwindcss": "^3.0.24"
},
"dependencies": {
"watch": "^1.0.2"
},
"watch": {
"css_build": "wwwroot/css/site.css"
} }
} }

View File

@@ -1,6 +1,9 @@
module.exports = { module.exports = {
plugins: { plugins: [
tailwindcss: {}, require('tailwindcss'),
autoprefixer: {},
}, // Production:
require('autoprefixer'),
require('cssnano')({ preset: 'default' })
],
} }

View File

@@ -31,7 +31,16 @@ module.exports = {
extend: { extend: {
colors: { colors: {
'hamannHighlight': '#d80000', 'hamannHighlight': '#d80000',
'hamannLightHighlight': '#cc7878' 'hamannLightHighlight': '#cc7878',
'hamannSlate': {
50: '#6A829E',
100: '#416C9E',
200: '#3F8FEB',
300: '#3270B8',
500: '#2B619E',
700: '#1E4570',
900: '#173557'
}
} }
}, },
}, },

File diff suppressed because one or more lines are too long

View File

@@ -158,6 +158,22 @@
@apply border-b-2 border-slate-200 @apply border-b-2 border-slate-200
} }
.ha-register .ha-register-head .ha-register-add a {
@apply rounded border border-black hover:shadow-md hover:border-hamannHighlight
}
.ha-register .ha-register-head .ha-register-add a .ha-register-add-plusbutton {
@apply rounded-l bg-slate-200
}
.ha-register .ha-register-head .ha-register-add a:hover .ha-register-add-plusbutton {
}
.ha-register .ha-register-head .ha-register-add a .ha-register-add-text {
}
.ha-register .ha-register-head .ha-register-nav a { .ha-register .ha-register-head .ha-register-nav a {
@apply text-slate-700 hover:text-slate-900 dark:text-white dark:hover:text-gray-300 @apply text-slate-700 hover:text-slate-900 dark:text-white dark:hover:text-gray-300
} }
@@ -173,7 +189,7 @@
.ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks::before, .ha-register .ha-neuzeit .ha-register-body .ha-commenthead .ha-letlinks::before,
.ha-register .ha-forschung .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 @apply bg-hamannSlate-500 dark:bg-slate-500
} }
.ha-register .ha-register-body .ha-commenthead .ha-letlinks.ha-expanded-box { .ha-register .ha-register-body .ha-commenthead .ha-letlinks.ha-expanded-box {
@@ -181,40 +197,39 @@
} }
.ha-register .ha-btn-collapsed-box { .ha-register .ha-btn-collapsed-box {
@apply hidden desktop:block absolute -top-[0.15rem] cursor-pointer @apply hidden desktop:block absolute -top-[0.15rem] cursor-pointer mt-0.5
} }
.ha-register .ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks .ha-hkb {
.ha-register-body
.ha-comment
.ha-commenthead
.ha-letlinks
.ha-hkb {
@apply text-slate-900 dark:text-white @apply text-slate-900 dark:text-white
} }
.ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks a { .ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks a {
@apply hover:text-slate-900 dark:hover:text-gray-200 no-underline hover:underline @apply hover:text-hamannSlate-900 dark:hover:text-gray-200 no-underline hover:underline
} }
.ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks { .ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks {
@apply text-slate-600 dark:text-white @apply text-slate-700 dark:text-white
} }
.ha-letterhead .ha-metadata .ha-tooltiptext { .ha-letterhead .ha-metadata .ha-tooltiptext {
@apply bg-slate-100 shadow @apply shadow-sm bg-slate-50 border-hamannSlate-900 text-hamannSlate-900 border dark:border-none dark:shadow dark:bg-slate-800
} }
.ha-tooltip .ha-tooltiptext::after { .ha-tooltip .ha-tooltiptext::after {
@apply border-t-slate-600 border-l-transparent border-r-transparent border-b-transparent @apply border-t-slate-600 dark:border-t-slate-800 border-l-transparent border-r-transparent border-b-transparent
} }
.ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill { .ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill {
@apply bg-slate-100 shadow dark:bg-gray-700 @apply rounded-lg border shadow-inner border-hamannSlate-900 text-hamannSlate-900 dark:text-white dark:bg-slate-800 dark:shadow-md dark:border-slate-400
}
.ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill.ha-newpill {
@apply dark:text-white dark:bg-slate-800 dark:shadow-md dark:border-slate-400
} }
.ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill .ha-cross::before { .ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill .ha-cross::before {
@apply border-b-2 border-gray-600 dark:border-gray-200 @apply border-b-2 border-hamannSlate-900 dark:border-gray-200
} }
.ha-letterheader { .ha-letterheader {
@@ -258,7 +273,7 @@
} }
.ha-linecount.ha-firstline { .ha-linecount.ha-firstline {
@apply sm:bg-slate-100 sm:dark:bg-gray-700 shadow @apply rounded-lg sm:border sm:bg-slate-50 sm:shadow-inner sm:border-slate-600 text-slate-800 dark:text-white sm:dark:bg-slate-800 sm:dark:shadow-md sm:dark:border-slate-400
} }
.ha-linecount .ha-zhpage, .ha-linecount .ha-zhpage,
@@ -268,7 +283,7 @@
.ha-tradzhtext .ha-marginal::before, .ha-tradzhtext .ha-marginal::before,
.ha-lettertext .ha-marginal:before { .ha-lettertext .ha-marginal:before {
@apply bg-slate-400 dark:bg-slate-500 @apply bg-hamannSlate-500 dark:bg-slate-500
} }
.ha-tradzhtext .ha-marginalbox, .ha-tradzhtext .ha-marginalbox,
@@ -359,6 +374,14 @@
@apply border-none @apply border-none
} }
.ha-scrollbutton {
@apply opacity-0 transition-opacity duration-500 cursor-pointer fixed left-[85%] text-center bottom-0 pb-3 pt-2 bg-slate-50 dark:bg-slate-700 dark:text-white px-2 shadow-md rounded-t-xl hover:shadow-lg text-hamannSlate-700 hover:text-hamannSlate-500
}
.ha-scrollbuttonarrow {
@apply h-8 w-8
}
/* Classes for the footer */ /* Classes for the footer */
.ha-footer { .ha-footer {
@apply font-serif; @apply font-serif;
@@ -435,7 +458,7 @@
} }
.ha-static p { .ha-static p {
@apply my-3 @apply my-4
} }
.ha-static a { .ha-static a {
@@ -473,6 +496,22 @@
@apply font-bold text-xl desktop:font-normal desktop:text-4xl mb-6 @apply font-bold text-xl desktop:font-normal desktop:text-4xl mb-6
} }
.ha-register .ha-register-head .ha-register-add a {
@apply -mt-4 mb-6 flex flex-row w-fit text-sm font-sans
}
.ha-register .ha-register-head .ha-register-add a .ha-register-add-plusbutton {
@apply px-2 leading-none text-xl font-bold pb-0.5
}
.ha-register .ha-register-head .ha-register-add a:hover .ha-register-add-plusbutton {
}
.ha-register .ha-register-head .ha-register-add a .ha-register-add-text {
@apply pl-1 pr-2 leading-none pt-1
}
.ha-register .ha-register-head .ha-register-nav { .ha-register .ha-register-head .ha-register-nav {
@apply font-sans @apply font-sans
} }
@@ -535,11 +574,11 @@
} }
.ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks { .ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks {
@apply inline-block font-normal text-xs md:text-sm leading-snug font-sans caps-allpetite ml-2 @apply inline-block font-normal text-xs md:text-sm leading-snug font-sans caps-allpetite ml-2 mt-1
} }
.ha-register .ha-register-body .ha-comment .ha-commenthead .ha-letlinks::before { .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-[''] @apply absolute mt-1 top-[0.1rem] bottom-[0.1rem] left-0 w-0.5 content-['']
} }
.ha-register .ha-register
@@ -637,7 +676,7 @@
} }
.ha-letterhead .ha-metadata .ha-tooltip { .ha-letterhead .ha-metadata .ha-tooltip {
@apply self-center cursor-default inline-block relative @apply self-center cursor-default inline-block relative
} }
.ha-letterhead .ha-metadata .ha-tooltiptext { .ha-letterhead .ha-metadata .ha-tooltiptext {
@@ -649,7 +688,7 @@
} }
.ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill { .ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill {
@apply text-xs rounded px-2 ml-2 py-[0.1rem] @apply text-sm rounded px-1.5 ml-2 py-0.5 leading-none caps-allpetite tracking-wide
} }
.ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill .ha-cross { .ha-letterhead .ha-metadata .ha-metadataupperrow .ha-pill .ha-cross {
@@ -679,7 +718,7 @@
} }
.ha-adminuploadfields .ha-uploadfield.active { .ha-adminuploadfields .ha-uploadfield.active {
@apply !text-black brightness-110 @apply !text-black brightness-110 shadow-inner
} }
.ha-adminuploadfields .ha-uploadfield .ha-uploadfieldname { .ha-adminuploadfields .ha-uploadfield .ha-uploadfieldname {
@@ -711,30 +750,22 @@
} }
.ha-adminuploadfields .ha-uploadform .ha-uploadfilelabel { .ha-adminuploadfields .ha-uploadform .ha-uploadfilelabel {
@apply inline-block px-2 py-1 pt-2 cursor-pointer w-full h-full hover:bg-slate-100 @apply inline-block px-4 py-1 pt-2 cursor-pointer w-full h-full hover:bg-slate-100
} }
.ha-adminuploadfields .ha-uploadform .ha-uploadmessage { .ha-adminuploadfields .ha-uploadform .ha-uploadmessage {
@apply text-sm bg-slate-700 bg-opacity-30 px-1 rounded-sm @apply text-sm bg-slate-700 bg-opacity-30 px-1 rounded-sm
} }
.ha-adminuploadfields .ha-publishform { .ha-adminuploadfields .ha-publishbutton {
@apply bg-slate-50 rounded shadow grow relative @apply inline-block px-2 py-1 pt-2 cursor-pointer w-full h-full bg-slate-50 shadow shrink hover:bg-slate-100
} }
.ha-adminuploadfields .ha-publishform .ha-lds-ellipsis { .ha-adminuploadfields .ha-publishbutton .ha-publishtext {
@apply left-1/2 -ml-[20px]
}
.ha-adminuploadfields .ha-publishform .ha-publishfilelabel {
@apply inline-block px-2 py-1 pt-2 cursor-pointer w-full h-full hover:bg-slate-100
}
.ha-adminuploadfields .ha-publishform .ha-publishtext {
@apply text-center @apply text-center
} }
.ha-adminuploadfields .ha-publishform .ha-publishmessage { .ha-adminuploadfields .ha-publishbutton .ha-publishmessage {
@apply text-sm bg-slate-700 bg-opacity-30 px-1 rounded-sm @apply text-sm bg-slate-700 bg-opacity-30 px-1 rounded-sm
} }
@@ -750,8 +781,24 @@
@apply w-full bg-slate-50 flex flex-col gap-y-2 h-full @apply w-full bg-slate-50 flex flex-col gap-y-2 h-full
} }
.ha-uploadcontainer .ha-publishfilelist {
@apply px-16 mb-8
}
.ha-uploadcontainer .ha-publishfilelist .ha-publishfilelisttitle {
@apply text-xl mb-2
}
.ha-uploadcontainer .ha-publishfilelist td {
@apply align-text-top pr-6
}
.ha-uploadcontainer .ha-publishfilelist .ha-publishfilelabel {
@apply relative mt-4 ml-6 rounded-md px-3 border-2 border-blue-600 hover:border-2 hover:shadow active:shadow-inner hover:border-blue-800 cursor-pointer float-right;
}
.ha-uploadcontainer .ha-availablefiles { .ha-uploadcontainer .ha-availablefiles {
@apply px-16 border border-slate-200 hover:border-slate-800 py-2 cursor-pointer @apply px-16 border border-slate-200 hover:border-slate-800 py-2 cursor-pointer select-none
} }
.ha-uploadcontainer .ha-availablefiles .ha-availablefilestitle { .ha-uploadcontainer .ha-availablefiles .ha-availablefilestitle {
@@ -809,7 +856,11 @@
} }
.ha-selectfilesform .ha-filelistfile { .ha-selectfilesform .ha-filelistfile {
@apply flex flex-row gap-x-4 @apply flex flex-row gap-x-4 px-1 items-center
}
.ha-selectfilesform .ha-filelistfile:nth-child(even) {
@apply bg-slate-100
} }
.ha-selectfilesform .ha-filelistlist { .ha-selectfilesform .ha-filelistlist {
@@ -821,7 +872,7 @@
} }
.ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction { .ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction {
@apply text-sm self-start @apply text-sm
} }
.ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction .ha-filelistproduction { .ha-selectfilesform .ha-filelistfile .ha-filelistusedproduction .ha-filelistproduction {
@@ -836,8 +887,12 @@
@apply grow text-right @apply grow text-right
} }
.ha-selectfilesform .ha-filelistoutput {
@apply mt-4 ml-6
}
.ha-selectfilesform .ha-filelistbutton { .ha-selectfilesform .ha-filelistbutton {
@apply mt-2 ml-6 rounded-md px-3 border-2 border-blue-700 hover:bg-blue-300 cursor-pointer float-right; @apply mt-4 ml-6 rounded-md px-3 border-2 border-blue-600 hover:border-2 hover:shadow active:shadow-inner hover:border-blue-800 cursor-pointer float-right;
} }
/* Classes for Letter View */ /* Classes for Letter View */
@@ -1033,7 +1088,7 @@
} }
.ha-linecount.ha-firstline { .ha-linecount.ha-firstline {
@apply hidden sm:inline-block rounded px-1 sm:pb-1 caps-allpetite normal-nums whitespace-nowrap @apply hidden sm:inline-block rounded px-1.5 sm:py-0.5 sm:pb-1 sm:leading-none caps-allpetite normal-nums whitespace-nowrap
} }
.ha-linecount { .ha-linecount {
@@ -1059,12 +1114,12 @@
.ha-tradzhtext .ha-marginal::before, .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-[''] @apply absolute top-[0.2rem] bottom-[0.1rem] left-0 w-0.5 content-['']
} }
.ha-tradzhtext .ha-marginalbox, .ha-tradzhtext .ha-marginalbox,
.ha-lettertext .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 rounded-sm font-sans @apply hidden select-none hover:select-auto hyphenate pl-2 md:block absolute left-full ml-2 desktop:ml-10 mt-1 w-[16rem] desktop:w-[28rem] text-sm leading-tight rounded-sm font-sans
} }
.ha-tradzhtext .ha-marginalbox .ha-marginallist, .ha-tradzhtext .ha-marginalbox .ha-marginallist,
@@ -1091,7 +1146,7 @@
.ha-tradzhtext .ha-btn-collapsed-box, .ha-tradzhtext .ha-btn-collapsed-box,
.ha-lettertext .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 @apply absolute left-full desktop:ml-7 hidden md:block cursor-pointer leading-none mt-0.5
} }
.ha-minwidth .ha-tradzhtext, .ha-minwidth .ha-tradzhtext,
@@ -1360,6 +1415,7 @@
/* Not implemented in tailwindcss */ /* Not implemented in tailwindcss */
* { * {
scroll-behavior: smooth;
text-decoration-skip-ink: all; text-decoration-skip-ink: all;
} }
@@ -1424,6 +1480,9 @@ body {
-webkit-text-decoration-skip-ink: auto; -webkit-text-decoration-skip-ink: auto;
} }
/* Missiung Tailwind classes */
.hyphenate { .hyphenate {
hyphens: auto; hyphens: auto;
} }
@@ -1452,6 +1511,7 @@ body {
font-variant-caps: normal; font-variant-caps: normal;
} }
.break-inside-avoid { .break-inside-avoid {
break-inside: avoid; break-inside: avoid;
} }
@@ -1568,7 +1628,23 @@ body {
bottom: 20px; bottom: 20px;
} }
.ha-lds-ellipsis div { .ha-lds-ellipsis-load {
display: none;
position: relative;
width: 38px;
bottom: 8px;
}
.ha-lds-ellipsis-publish {
display: none;
position: absolute;
left: -50px;
bottom: 16px;
}
.ha-lds-ellipsis div,
.ha-lds-ellipsis-load div,
.ha-lds-ellipsis-publish div {
position: absolute; position: absolute;
width: 7px; width: 7px;
height: 7px; height: 7px;
@@ -1577,22 +1653,30 @@ body {
animation-timing-function: cubic-bezier(0, 1, 1, 0); animation-timing-function: cubic-bezier(0, 1, 1, 0);
} }
.ha-lds-ellipsis div:nth-child(1) { .ha-lds-ellipsis div:nth-child(1),
.ha-lds-ellipsis-load div:nth-child(1),
.ha-lds-ellipsis-publish div:nth-child(1) {
left: 6px; left: 6px;
animation: ha-lds-ellipsis1 0.6s infinite; animation: ha-lds-ellipsis1 0.6s infinite;
} }
.ha-lds-ellipsis div:nth-child(2) { .ha-lds-ellipsis div:nth-child(2),
.ha-lds-ellipsis-load div:nth-child(2),
.ha-lds-ellipsis-publish div:nth-child(2) {
left: 4px; left: 4px;
animation: ha-lds-ellipsis2 0.6s infinite; animation: ha-lds-ellipsis2 0.6s infinite;
} }
.ha-lds-ellipsis div:nth-child(3) { .ha-lds-ellipsis div:nth-child(3),
.ha-lds-ellipsis-load div:nth-child(3),
.ha-lds-ellipsis-publish div:nth-child(3) {
left: 16px; left: 16px;
animation: ha-lds-ellipsis2 0.6s infinite; animation: ha-lds-ellipsis2 0.6s infinite;
} }
.ha-lds-ellipsis div:nth-child(4) { .ha-lds-ellipsis div:nth-child(4),
.ha-lds-ellipsis-load div:nth-child(4),
.ha-lds-ellipsis-publish div:nth-child(4) {
left: 30px; left: 30px;
animation: ha-lds-ellipsis3 0.6s infinite; animation: ha-lds-ellipsis3 0.6s infinite;
} }

View File

@@ -1,3 +1,4 @@
// Functions for opening and closing the menu on mobile devices
const openmenu = function () { const openmenu = function () {
var x = document.getElementById("ha-topnav"); var x = document.getElementById("ha-topnav");
if (x !== null) x.className += " ha-topnav-collapsed"; if (x !== null) x.className += " ha-topnav-collapsed";
@@ -31,18 +32,20 @@ const markactive_startswith = function (element) {
}; };
const markactive_exact = function (element) { const markactive_exact = function (element) {
// Marks links active which target URL is exact the same as the current URL
var all_links = element.getElementsByTagName("a"), var all_links = element.getElementsByTagName("a"),
i = 0, i = 0,
len = all_links.length, len = all_links.length,
full_path = location.href.split("#")[0].toLowerCase(); //Ignore hashes full_path = location.href.split("#")[0].toLowerCase(); //Ignore hashes
for (; i < len; i++) { for (; i < len; i++) {
if (full_path == all_links[i].href.toLowerCase()) { if (full_path == all_links[i].href.toLowerCase() || full_path == all_links[i].href.toLowerCase() + "/") {
all_links[i].className += " active"; all_links[i].className += " active";
} }
} }
}; };
// Functions for collapsing marginals, and adding a button next to those
const getLineHeight = function (element) { const getLineHeight = function (element) {
var temp = document.createElement(element.nodeName), var temp = document.createElement(element.nodeName),
ret; ret;
@@ -122,7 +125,6 @@ const addbuttoncaollapsebox = function (element, height, hoverfunction) {
element.parentNode.insertBefore(btn, element); element.parentNode.insertBefore(btn, element);
}; };
/* TODO: need a resize watcher to undo and reapply the effect on breakpoint */
const overlappingcollapsebox = function (selector, hoverfunction) { const overlappingcollapsebox = function (selector, hoverfunction) {
let boxes = document.querySelectorAll(selector); let boxes = document.querySelectorAll(selector);
let lineheight = 1; let lineheight = 1;
@@ -172,6 +174,22 @@ const overlappingcollapsebox = function (selector, hoverfunction) {
} }
}; };
const marginalboxwidthset = function() {
let lt = document.getElementById("ha-letterbody");
if (lt !== null) {
let mg = lt.querySelectorAll(".ha-lettertext .ha-marginalbox");
if (mg.length > 0) {
let ltbcr = lt.getBoundingClientRect();
let mgbcr = mg[0].getBoundingClientRect();
let nw = ltbcr.right - mgbcr.left - 18;
for (let element of mg) {
element.style.width = nw + "px";
}
}
}
}
/* Button to hide / show traditions, marginals and the text of the letter */ /* Button to hide / show traditions, marginals and the text of the letter */
const showhidebutton = function ( const showhidebutton = function (
buttonid, buttonid,
@@ -215,6 +233,11 @@ const showhidebutton = function (
} }
}; };
const collapseboxes = function () {
overlappingcollapsebox(".ha-neuzeit .ha-letlinks", true);
overlappingcollapsebox(".ha-forschung .ha-letlinks", true);
overlappingcollapsebox(".ha-lettertext .ha-marginalbox", true);
};
// Functions for switching theme // Functions for switching theme
const go_to_dark = function () { const go_to_dark = function () {
localStorage.setItem("theme", "ha-toggledark"); localStorage.setItem("theme", "ha-toggledark");
@@ -233,14 +256,26 @@ const get_theme_settings = function (standard) {
let toggleSwitch = document.getElementById(theme).click(); let toggleSwitch = document.getElementById(theme).click();
}; };
const collapseboxes = function () { // Functions for scrolling
overlappingcollapsebox(".ha-neuzeit .ha-letlinks", true); const scrollFunction = function () {
overlappingcollapsebox(".ha-forschung .ha-letlinks", true); button = document.getElementById("ha-scrollbutton");
overlappingcollapsebox(".ha-lettertext .ha-marginalbox", true); if (document.body.scrollTop > 300 || document.documentElement.scrollTop > 300) {
}; button.style.opacity = "1";
} else {
button.style.opacity = "0";
}
}
//////////////////////////////// ONLOAD //////////////////////////////////// //////////////////////////////// ONLOAD ////////////////////////////////////
window.addEventListener("load", function () { window.addEventListener("load", function () {
// Scroll button
let scrollbutton = this.document.getElementById("ha-scrollbutton");
scrollbutton.addEventListener("click", () => {
document.body.scrollTop = 0; // For Safari
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
})
this.window.addEventListener("scroll", scrollFunction);
// Menu: Show / Hide Buttons for mobile View // Menu: Show / Hide Buttons for mobile View
if ( if (
document.getElementById("openmenubutton") !== null && document.getElementById("openmenubutton") !== null &&
@@ -260,14 +295,16 @@ window.addEventListener("load", function () {
if (document.getElementById("ha-register-nav") != null) if (document.getElementById("ha-register-nav") != null)
markactive_exact(document.getElementById("ha-register-nav")); markactive_exact(document.getElementById("ha-register-nav"));
if (this.document.getElementById("ha-adminuploadfields") != null) if (this.document.getElementById("ha-adminuploadfields") != null)
markactive_startswith(document.getElementById("ha-adminuploadfields")); markactive_exact(document.getElementById("ha-adminuploadfields"));
// Letter / Register View: Collapse all unfit boxes + resize observer // Letter / Register View: Collapse all unfit boxes + resize observer
marginalboxwidthset();
collapseboxes(); collapseboxes();
var doit; var doit;
this.window.addEventListener("resize", function () { this.window.addEventListener("resize", function () {
this.clearTimeout(doit); this.clearTimeout(doit);
this.setTimeout(collapseboxes, 250); marginalboxwidthset();
doit = this.setTimeout(collapseboxes, 250);
}); });
// Letter View: Show / Hide Tabs // Letter View: Show / Hide Tabs