Compare commits
5 commits
b61ec6b165
...
9e47e64dbb
Author | SHA1 | Date | |
---|---|---|---|
9e47e64dbb | |||
107fe6078c | |||
e5748ec8d5 | |||
9a25bc406f | |||
68c6fe6395 |
23 changed files with 247 additions and 34 deletions
7
.vscode/tasks.json
vendored
7
.vscode/tasks.json
vendored
|
@ -41,6 +41,13 @@
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "typescript",
|
||||||
|
"label": "ts watch",
|
||||||
|
"tsconfig": ".vscode/tsconfig.json",
|
||||||
|
"problemMatcher": "$tsc-watch",
|
||||||
|
"group": "build"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
11
.vscode/tsconfig.json
vendored
Normal file
11
.vscode/tsconfig.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"compileOnSave": true,
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES6",
|
||||||
|
"sourceMap": true,
|
||||||
|
"watch": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"../wwwroot/js"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Snootalogue.Models;
|
using Snootalogue.Models;
|
||||||
|
@ -21,7 +22,7 @@ namespace Snootalogue.Controllers {
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<ActionResult<Document>> GetDocumentById(int id) {
|
public async Task<ActionResult<Document>> GetDocumentById(string id) {
|
||||||
var document = await _context.Document.FindAsync(id);
|
var document = await _context.Document.FindAsync(id);
|
||||||
|
|
||||||
if (document == null) {
|
if (document == null) {
|
||||||
|
@ -30,5 +31,21 @@ namespace Snootalogue.Controllers {
|
||||||
|
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public async Task<ActionResult<bool>> DeleteDocument(string id) {
|
||||||
|
var document = await _context.Document.FindAsync(id);
|
||||||
|
if (document == null) {
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var uploadDirectory = Path.Combine("wwwroot", "Content");
|
||||||
|
var destination = Path.Combine(uploadDirectory, $"{id}.pdf");
|
||||||
|
System.IO.File.Delete(destination);
|
||||||
|
|
||||||
|
_context.Remove(document);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ using Snootalogue.Data;
|
||||||
namespace snootalogue.Migrations
|
namespace snootalogue.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(SnootalogueContext))]
|
[DbContext(typeof(SnootalogueContext))]
|
||||||
[Migration("20200917125618_InitialCreate")]
|
[Migration("20200920033715_InitialCreate")]
|
||||||
partial class InitialCreate
|
partial class InitialCreate
|
||||||
{
|
{
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
@ -20,9 +20,8 @@ namespace snootalogue.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("Snootalogue.Models.Document", b =>
|
modelBuilder.Entity("Snootalogue.Models.Document", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ID")
|
b.Property<string>("ID")
|
||||||
.ValueGeneratedOnAdd()
|
.HasColumnType("TEXT");
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Authors")
|
b.Property<string>("Authors")
|
||||||
.HasColumnType("jsonb");
|
.HasColumnType("jsonb");
|
|
@ -11,8 +11,7 @@ namespace snootalogue.Migrations
|
||||||
name: "Document",
|
name: "Document",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
ID = table.Column<int>(nullable: false)
|
ID = table.Column<string>(nullable: false),
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
Filename = table.Column<string>(nullable: true),
|
Filename = table.Column<string>(nullable: true),
|
||||||
Hash = table.Column<string>(nullable: true),
|
Hash = table.Column<string>(nullable: true),
|
||||||
Size = table.Column<long>(nullable: false),
|
Size = table.Column<long>(nullable: false),
|
|
@ -18,9 +18,8 @@ namespace snootalogue.Migrations
|
||||||
|
|
||||||
modelBuilder.Entity("Snootalogue.Models.Document", b =>
|
modelBuilder.Entity("Snootalogue.Models.Document", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ID")
|
b.Property<string>("ID")
|
||||||
.ValueGeneratedOnAdd()
|
.HasColumnType("TEXT");
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Authors")
|
b.Property<string>("Authors")
|
||||||
.HasColumnType("jsonb");
|
.HasColumnType("jsonb");
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Snootalogue.Data;
|
||||||
|
using System.Runtime;
|
||||||
|
|
||||||
namespace Snootalogue.Models {
|
namespace Snootalogue.Models {
|
||||||
public class Document {
|
public class Document {
|
||||||
public int ID { get; set; }
|
public string ID { get; set; }
|
||||||
public string Filename { get; set; }
|
public string Filename { get; set; }
|
||||||
public string Hash { get; set; }
|
public string Hash { get; set; }
|
||||||
[UIHint("FileSize")]
|
[UIHint("FileSize")]
|
||||||
|
@ -20,5 +22,24 @@ namespace Snootalogue.Models {
|
||||||
public List<string> Tags { get; set; }
|
public List<string> Tags { get; set; }
|
||||||
public Boolean Read { get; set; }
|
public Boolean Read { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
|
||||||
|
public static string NewID(SnootalogueContext context) {
|
||||||
|
// - no vowels to avoid (most) (non-welsh) naughty words
|
||||||
|
// - no l1I because it's always confusing
|
||||||
|
// - no 0
|
||||||
|
string idCharacters = "bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ23456789";
|
||||||
|
var rng = new Random();
|
||||||
|
var collision = true;
|
||||||
|
string id = "";
|
||||||
|
while (collision) {
|
||||||
|
id = "";
|
||||||
|
for (var i = 0; i < 7; i++) {
|
||||||
|
id += idCharacters[rng.Next(idCharacters.Length)];
|
||||||
|
}
|
||||||
|
collision = context.Document.Find(id) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Snootalogue.Models {
|
||||||
|
|
||||||
context.Document.AddRange(
|
context.Document.AddRange(
|
||||||
new Document {
|
new Document {
|
||||||
|
ID = Document.NewID(context),
|
||||||
Title = "The Peebler Chronicles",
|
Title = "The Peebler Chronicles",
|
||||||
Filename = "peebler.pdf",
|
Filename = "peebler.pdf",
|
||||||
Size = Convert.ToInt64(0.5 * 1024 * 1024),
|
Size = Convert.ToInt64(0.5 * 1024 * 1024),
|
||||||
|
@ -27,6 +28,7 @@ namespace Snootalogue.Models {
|
||||||
Hash = "0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0"
|
Hash = "0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0"
|
||||||
},
|
},
|
||||||
new Document {
|
new Document {
|
||||||
|
ID = Document.NewID(context),
|
||||||
Title = "Smooched by a Wifeoid",
|
Title = "Smooched by a Wifeoid",
|
||||||
Filename = "smooched_by_a_wifeoid.pdf",
|
Filename = "smooched_by_a_wifeoid.pdf",
|
||||||
Size = 7 * 1024 * 1024,
|
Size = 7 * 1024 * 1024,
|
||||||
|
@ -37,6 +39,7 @@ namespace Snootalogue.Models {
|
||||||
Hash = "0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0"
|
Hash = "0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0"
|
||||||
},
|
},
|
||||||
new Document {
|
new Document {
|
||||||
|
ID = Document.NewID(context),
|
||||||
Title = "What on Boo Earth? My Girlfriend can Walk on the Ceiling?!",
|
Title = "What on Boo Earth? My Girlfriend can Walk on the Ceiling?!",
|
||||||
Filename = "ceiling_gf.pdf",
|
Filename = "ceiling_gf.pdf",
|
||||||
Size = Convert.ToInt64(22.5 * 1024 * 1024),
|
Size = Convert.ToInt64(22.5 * 1024 * 1024),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@page "{id:int}"
|
@page "{id}"
|
||||||
@model Snootalogue.Pages.Documents.DetailsModel
|
@model Snootalogue.Pages.Documents.DetailsModel
|
||||||
|
|
||||||
@{
|
@{
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Snootalogue.Pages.Documents {
|
||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnGetAsync(int? id) {
|
public async Task<IActionResult> OnGetAsync(string id) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@page "{id:int}"
|
@page "{id}"
|
||||||
@model Snootalogue.Pages.Documents.EditModel
|
@model Snootalogue.Pages.Documents.EditModel
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Snootalogue.Pages.Documents {
|
||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnGetAsync(int? id) {
|
public async Task<IActionResult> OnGetAsync(string id) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
@page "{id:int}"
|
@page "{id}"
|
||||||
@model Snootalogue.Pages.Documents.ViewModel
|
@model Snootalogue.Pages.Documents.ViewModel
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Viewing \"{Model.Document.Title}\"";
|
ViewData["Title"] = $"Viewing \"{Model.Document.Title}\"";
|
||||||
ViewData["SlimNavbar"] = true;
|
ViewData["SlimNavbar"] = true;
|
||||||
ViewData["NoMainPadding"] = true;
|
ViewData["NoMainPadding"] = true;
|
||||||
|
string path = $"/Content/{Model.Document.ID}.pdf";
|
||||||
}
|
}
|
||||||
|
|
||||||
<iframe id="document-viewer" src="/Content/@Model.Document.Filename"></iframe>
|
<iframe id="document-viewer" src="@path"></iframe>
|
|
@ -14,7 +14,7 @@ namespace Snootalogue.Pages.Documents {
|
||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnGetAsync(int? id) {
|
public async Task<IActionResult> OnGetAsync(string id) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<div class="vertical-buttons">
|
<div class="vertical-buttons">
|
||||||
<a asp-page="./Documents/Details" asp-route-id="@item.ID" class="button simple">Details</a>
|
<a asp-page="./Documents/Details" asp-route-id="@item.ID" class="button simple">Details</a>
|
||||||
<a asp-page="./Documents/Edit" asp-route-id="@item.ID" class="button simple">Edit</a>
|
<a asp-page="./Documents/Edit" asp-route-id="@item.ID" class="button simple">Edit</a>
|
||||||
<a href="#" class="button simple">Delete</a>
|
<button class="button simple" onclick="PromptForDeletion('@item.ID', '@item.Filename')">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>@ViewData["Title"] | Snootalogue</title>
|
<title>@ViewData["Title"] | Snootalogue</title>
|
||||||
<link rel="stylesheet" href="~/css/style.css">
|
<link rel="stylesheet" href="~/css/style.css">
|
||||||
|
<script src="~/js/script.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -26,6 +27,16 @@
|
||||||
<footer>
|
<footer>
|
||||||
Made by <a href="https://lynnesbian.space">Lynnesbian</a>. Licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">Affero GNU Public License 3.0</a>. <a href="https://git.bune.city/lynnesbian/Snootalogue">Source code available</a>.
|
Made by <a href="https://lynnesbian.space">Lynnesbian</a>. Licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">Affero GNU Public License 3.0</a>. <a href="https://git.bune.city/lynnesbian/Snootalogue">Source code available</a>.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<div id="msgbox-holder">
|
||||||
|
<div id="msgbox">
|
||||||
|
<h1 id="msgbox-title">Message title</h1>
|
||||||
|
<div id="msgbox-message">This is the message</div>
|
||||||
|
<div id="msgbox-buttons">
|
||||||
|
@* buttons added by script.js here *@
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -32,10 +32,10 @@ namespace Snootalogue.Pages {
|
||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
var filename = WebUtility.HtmlEncode(ud.UploadedFile.FileName);
|
var id = Document.NewID(_context);
|
||||||
// var uploadDirectory = Path.Combine(filename);
|
// var uploadDirectory = Path.Combine(filename);
|
||||||
var uploadDirectory = "wwwroot/Content";
|
var uploadDirectory = Path.Combine("wwwroot", "Content");
|
||||||
var destination = Path.Combine(uploadDirectory, filename);
|
var destination = Path.Combine(uploadDirectory, $"{id}.pdf");
|
||||||
|
|
||||||
using (var fs = new FileStream(destination, FileMode.Create)) {
|
using (var fs = new FileStream(destination, FileMode.Create)) {
|
||||||
await ud.UploadedFile.CopyToAsync(fs);
|
await ud.UploadedFile.CopyToAsync(fs);
|
||||||
|
@ -43,13 +43,14 @@ namespace Snootalogue.Pages {
|
||||||
|
|
||||||
// Document d = _context.Document.
|
// Document d = _context.Document.
|
||||||
Document d = new Document {
|
Document d = new Document {
|
||||||
|
ID = id,
|
||||||
Title = ud.Title,
|
Title = ud.Title,
|
||||||
Authors = ud.Authors.Split(",").ToList<string>(),
|
Authors = ud.Authors.Split(",").ToList<string>(),
|
||||||
Category = ud.Category,
|
Category = ud.Category,
|
||||||
Tags = string.IsNullOrWhiteSpace(ud.Tags) ? null : ud.Tags.Split(",").ToList<string>(),
|
Tags = string.IsNullOrWhiteSpace(ud.Tags) ? null : ud.Tags.Split(",").ToList<string>(),
|
||||||
Notes = ud.Notes,
|
Notes = ud.Notes,
|
||||||
Read = ud.Read,
|
Read = ud.Read,
|
||||||
Filename = filename
|
Filename = WebUtility.HtmlEncode(ud.UploadedFile.FileName)
|
||||||
};
|
};
|
||||||
|
|
||||||
_context.Document.Add(d);
|
_context.Document.Add(d);
|
||||||
|
|
|
@ -16,6 +16,7 @@ Snootalogue runs on port **5000**, so make sure you don't have anything currentl
|
||||||
```bash
|
```bash
|
||||||
git clone https://git.bune.city/lynnesbian/Snootalogue
|
git clone https://git.bune.city/lynnesbian/Snootalogue
|
||||||
cd Snootalogue
|
cd Snootalogue
|
||||||
|
mkdir wwwroot/Content
|
||||||
if ! which dotnet-ef; then dotnet tool install --global dotnet-ef; fi
|
if ! which dotnet-ef; then dotnet tool install --global dotnet-ef; fi
|
||||||
dotnet ef database update
|
dotnet ef database update
|
||||||
dotnet run
|
dotnet run
|
||||||
|
|
|
@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations;
|
||||||
namespace Snootalogue.ViewModels {
|
namespace Snootalogue.ViewModels {
|
||||||
public class EditDocument {
|
public class EditDocument {
|
||||||
[Required]
|
[Required]
|
||||||
public int ID { get; set; }
|
public string ID { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
html, body, main {
|
||||||
|
height: 100%; /* needed for chromium to display the #document-viewer at 100% height */
|
||||||
|
}
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
@ -31,7 +34,7 @@ a:not(.button):hover {
|
||||||
text-decoration: underline dotted;
|
text-decoration: underline dotted;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button, button {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
color: #a66;
|
color: #a66;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
@ -41,19 +44,19 @@ a:not(.button):hover {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: 0.2s all;
|
transition: 0.2s all;
|
||||||
}
|
}
|
||||||
.button:hover {
|
.button:hover, button:hover {
|
||||||
background: #a66;
|
background: #a66;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
.button.block {
|
.button.block, button.block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 5px auto;
|
margin: 5px auto;
|
||||||
}
|
}
|
||||||
.button.inverted {
|
.button.inverted, button.inverted {
|
||||||
color: white;
|
color: white;
|
||||||
border-color: white;
|
border-color: white;
|
||||||
}
|
}
|
||||||
.button.inverted:hover {
|
.button.inverted:hover, button.inverted:hover {
|
||||||
background: white;
|
background: white;
|
||||||
color: #a00;
|
color: #a00;
|
||||||
}
|
}
|
||||||
|
@ -62,15 +65,18 @@ a:not(.button):hover {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.vertical-buttons .button {
|
.vertical-buttons .button,
|
||||||
|
.vertical-buttons button {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
.vertical-buttons .button:first-child {
|
.vertical-buttons .button:first-child,
|
||||||
|
.vertical-buttons button:first-child {
|
||||||
border-radius: 5px 5px 0 0;
|
border-radius: 5px 5px 0 0;
|
||||||
}
|
}
|
||||||
.vertical-buttons .button:last-child {
|
.vertical-buttons .button:last-child,
|
||||||
|
.vertical-buttons button:last-child {
|
||||||
border-bottom: thin #a66 solid;
|
border-bottom: thin #a66 solid;
|
||||||
border-radius: 0 0 5px 5px;
|
border-radius: 0 0 5px 5px;
|
||||||
}
|
}
|
||||||
|
@ -120,6 +126,35 @@ footer {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#msgbox-holder {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
background: #6668;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
#msgbox {
|
||||||
|
background: #833;
|
||||||
|
color: white;
|
||||||
|
padding: 40px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1em;
|
||||||
|
margin-bottom: 50px; /* to make it slightly higher than the centre of the page */
|
||||||
|
}
|
||||||
|
#msgbox h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
#msgbox-message {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
#msgbox-buttons > button {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.documents {
|
.documents {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -203,7 +238,7 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
.button {
|
.button, button {
|
||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
wwwroot/js/script.js
Normal file
46
wwwroot/js/script.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
;
|
||||||
|
var standardCancelButton = {
|
||||||
|
message: "Cancel",
|
||||||
|
onClick: function () { }
|
||||||
|
};
|
||||||
|
function DoHTTPRequest(url, method = "GET") {
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.onreadystatechange = function () {
|
||||||
|
// console.log(this);
|
||||||
|
if (this.readyState == 4) {
|
||||||
|
if (this.status == 200) {
|
||||||
|
return { success: true, response: this.responseText };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { success: false, response: `HTTP status ${this.status}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
request.open(method, url);
|
||||||
|
request.send();
|
||||||
|
return { success: false, response: "Unknown error" };
|
||||||
|
}
|
||||||
|
function dgel(id) {
|
||||||
|
return document.getElementById(id);
|
||||||
|
}
|
||||||
|
function MessageBox(title, message, buttons, data) {
|
||||||
|
dgel("msgbox-title").textContent = title;
|
||||||
|
dgel("msgbox-message").textContent = message;
|
||||||
|
dgel("msgbox-buttons").innerHTML = "";
|
||||||
|
buttons.forEach(button => {
|
||||||
|
var htmlButton = document.createElement("button");
|
||||||
|
htmlButton.className = "inverted";
|
||||||
|
htmlButton.textContent = button.message;
|
||||||
|
htmlButton.addEventListener("click", function () { dgel("msgbox-holder").style.display = "none"; button.onClick(data); });
|
||||||
|
dgel("msgbox-buttons").appendChild(htmlButton);
|
||||||
|
});
|
||||||
|
dgel("msgbox-holder").style.display = "flex";
|
||||||
|
}
|
||||||
|
function PromptForDeletion(id, filename) {
|
||||||
|
MessageBox("Delete document?", `Are you sure you want to delete ${filename}?`, [{ message: "Delete", onClick: DeleteDocument }, standardCancelButton], id);
|
||||||
|
}
|
||||||
|
function DeleteDocument(id) {
|
||||||
|
DoHTTPRequest(`/api/Document/${id}`, "DELETE");
|
||||||
|
window.location = window.location;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=script.js.map
|
1
wwwroot/js/script.js.map
Normal file
1
wwwroot/js/script.js.map
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"script.js","sourceRoot":"","sources":["script.ts"],"names":[],"mappings":"AAGC,CAAC;AAEF,IAAI,oBAAoB,GAAqB;IAC5C,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,cAAc,CAAC;CACxB,CAAA;AAED,SAAS,aAAa,CAAC,GAAW,EAAE,SAAiB,KAAK;IACzD,IAAI,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;IACnC,OAAO,CAAC,kBAAkB,GAAG;QAC5B,qBAAqB;QACrB,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE;YACzB,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,EAAE;gBACvB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;aACtD;iBAAM;gBACN,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,eAAe,IAAI,CAAC,MAAM,EAAE,EAAE,CAAA;aACjE;SACD;IACF,CAAC,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,CAAC,IAAI,EAAE,CAAC;IAEf,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;AACtD,CAAC;AAED,SAAS,IAAI,CAAC,EAAU;IACvB,OAAO,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,UAAU,CAAC,KAAa,EAAE,OAAe,EAAE,OAAgC,EAAE,IAAU;IAC/F,IAAI,CAAC,cAAc,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC;IACzC,IAAI,CAAC,gBAAgB,CAAC,CAAC,WAAW,GAAG,OAAO,CAAC;IAC7C,IAAI,CAAC,gBAAgB,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC;IAEtC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;QACxB,IAAI,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAClD,UAAU,CAAC,SAAS,GAAG,UAAU,CAAC;QAClC,UAAU,CAAC,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC;QACxC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA,CAAC,CAAC,CAAC,CAAC;QACzH,IAAI,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;AAC9C,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAU,EAAE,QAAgB;IACtD,UAAU,CACT,kBAAkB,EAClB,mCAAmC,QAAQ,GAAG,EAC9C,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,oBAAoB,CAAC,EACtE,EAAE,CACF,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,EAAU;IACjC,aAAa,CAAC,iBAAiB,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC/C,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AACnC,CAAC"}
|
61
wwwroot/js/script.ts
Normal file
61
wwwroot/js/script.ts
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
interface MessageBoxButton {
|
||||||
|
message: string,
|
||||||
|
onClick: (data: any) => any,
|
||||||
|
};
|
||||||
|
|
||||||
|
var standardCancelButton: MessageBoxButton = {
|
||||||
|
message: "Cancel",
|
||||||
|
onClick: function () { }
|
||||||
|
}
|
||||||
|
|
||||||
|
function DoHTTPRequest(url: string, method: string = "GET"): { success: boolean, response: string } {
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.onreadystatechange = function () {
|
||||||
|
// console.log(this);
|
||||||
|
if (this.readyState == 4) {
|
||||||
|
if (this.status == 200) {
|
||||||
|
return { success: true, response: this.responseText };
|
||||||
|
} else {
|
||||||
|
return { success: false, response: `HTTP status ${this.status}` }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.open(method, url);
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
return { success: false, response: "Unknown error" };
|
||||||
|
}
|
||||||
|
|
||||||
|
function dgel(id: string): HTMLElement {
|
||||||
|
return document.getElementById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MessageBox(title: string, message: string, buttons: Array<MessageBoxButton>, data?: any) {
|
||||||
|
dgel("msgbox-title").textContent = title;
|
||||||
|
dgel("msgbox-message").textContent = message;
|
||||||
|
dgel("msgbox-buttons").innerHTML = "";
|
||||||
|
|
||||||
|
buttons.forEach(button => {
|
||||||
|
var htmlButton = document.createElement("button");
|
||||||
|
htmlButton.className = "inverted";
|
||||||
|
htmlButton.textContent = button.message;
|
||||||
|
htmlButton.addEventListener("click", function () { dgel("msgbox-holder").style.display = "none"; button.onClick(data) });
|
||||||
|
dgel("msgbox-buttons").appendChild(htmlButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
dgel("msgbox-holder").style.display = "flex";
|
||||||
|
}
|
||||||
|
|
||||||
|
function PromptForDeletion(id: string, filename: string) {
|
||||||
|
MessageBox(
|
||||||
|
"Delete document?",
|
||||||
|
`Are you sure you want to delete ${filename}?`,
|
||||||
|
[{ message: "Delete", onClick: DeleteDocument }, standardCancelButton],
|
||||||
|
id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DeleteDocument(id: string) {
|
||||||
|
DoHTTPRequest(`/api/Document/${id}`, "DELETE");
|
||||||
|
window.location = window.location;
|
||||||
|
}
|
Loading…
Reference in a new issue