Add path prefix

This commit is contained in:
Lars Westermann 2019-06-10 10:09:36 +02:00
parent 19956ebafb
commit afbced61e3
Signed by: lars.westermann
GPG key ID: 9D417FA5BB9D5E1D
39 changed files with 656 additions and 305 deletions

View file

@ -11,7 +11,8 @@ import org.w3c.dom.events.Event
import kotlin.browser.window
class WebSocketClient() {
private val url = "ws://${window.location.host}/"
val prefix = js("prefix")
private val url = "ws://${window.location.host}$prefix/"
private lateinit var ws: WebSocket
private var reconnect = false

View file

@ -11,6 +11,8 @@ import kotlinx.serialization.list
object PostRepository : Repository<Post> {
val prefix = js("prefix")
override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>()
@ -18,35 +20,35 @@ object PostRepository : Repository<Post> {
private val parser = DynamicObjectParser()
override suspend fun get(id: Long): Post? {
val json = repositoryGet("/api/post/$id") ?: return null
val json = repositoryGet("$prefix/api/post/$id") ?: return null
return parser.parse(json, Post.serializer())
}
override suspend fun create(model: Post): Long {
return repositoryPost("/api/posts", Message.json.stringify(Post.serializer(), model))
return repositoryPost("$prefix/api/posts", Message.json.stringify(Post.serializer(), model))
?: throw IllegalStateException("Cannot create model!")
}
override suspend fun update(model: Post) {
if (model.id == null) throw IllegalStateException("Cannot update model which was not created!")
repositoryPost("/api/post/${model.id}", Message.json.stringify(Post.serializer(), model))
repositoryPost("$prefix/api/post/${model.id}", Message.json.stringify(Post.serializer(), model))
}
override suspend fun delete(id: Long) {
repositoryPost("/api/post/$id/delete")
repositoryPost("$prefix/api/post/$id/delete")
}
override suspend fun all(): List<Post> {
val json = repositoryGet("/api/posts") ?: return emptyList()
val json = repositoryGet("$prefix/api/posts") ?: return emptyList()
return parser.parse(json, Post.serializer().list)
}
suspend fun htmlByUrl(url: String): String {
return repositoryRawGet("/api/p/$url")
return repositoryRawGet("$prefix/api/p/$url")
}
suspend fun render(data: String): String {
return repositoryPost("/api/render", data)
return repositoryPost("$prefix/api/render", data)
}
val handler = object : MessageHandler(RepositoryType.POST) {

View file

@ -11,6 +11,8 @@ import kotlinx.serialization.list
object RoomRepository : Repository<Room> {
val prefix = js("prefix")
override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>()
@ -18,26 +20,26 @@ object RoomRepository : Repository<Room> {
private val parser = DynamicObjectParser()
override suspend fun get(id: Long): Room? {
val json = repositoryGet("/api/room/$id") ?: return null
val json = repositoryGet("$prefix/api/room/$id") ?: return null
return parser.parse(json, Room.serializer())
}
override suspend fun create(model: Room): Long {
return repositoryPost("/api/rooms", Message.json.stringify(Room.serializer(), model))
return repositoryPost("$prefix/api/rooms", Message.json.stringify(Room.serializer(), model))
?: throw IllegalStateException("Cannot create model!")
}
override suspend fun update(model: Room) {
if (model.id == null) throw IllegalStateException("Cannot update model which was not created!")
repositoryPost("/api/room/${model.id}", Message.json.stringify(Room.serializer(), model))
repositoryPost("$prefix/api/room/${model.id}", Message.json.stringify(Room.serializer(), model))
}
override suspend fun delete(id: Long) {
repositoryPost("/api/room/$id/delete")
repositoryPost("$prefix/api/room/$id/delete")
}
override suspend fun all(): List<Room> {
val json = repositoryGet("/api/rooms") ?: return emptyList()
val json = repositoryGet("$prefix/api/rooms") ?: return emptyList()
return parser.parse(json, Room.serializer().list)
}

View file

@ -12,6 +12,8 @@ import kotlinx.serialization.list
object ScheduleRepository : Repository<Schedule> {
val prefix = js("prefix")
override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>()
@ -19,26 +21,26 @@ object ScheduleRepository : Repository<Schedule> {
private val parser = DynamicObjectParser()
override suspend fun get(id: Long): Schedule? {
val json = repositoryGet("/api/schedule/$id") ?: return null
val json = repositoryGet("$prefix/api/schedule/$id") ?: return null
return parser.parse(json, Schedule.serializer())
}
override suspend fun create(model: Schedule): Long {
return repositoryPost("/api/schedules", Message.json.stringify(Schedule.serializer(), model))
return repositoryPost("$prefix/api/schedules", Message.json.stringify(Schedule.serializer(), model))
?: throw IllegalStateException("Cannot create model!")
}
override suspend fun update(model: Schedule) {
if (model.id == null) throw IllegalStateException("Cannot update model which was not created!")
repositoryPost("/api/schedule/${model.id}", Message.json.stringify(Schedule.serializer(), model))
repositoryPost("$prefix/api/schedule/${model.id}", Message.json.stringify(Schedule.serializer(), model))
}
override suspend fun delete(id: Long) {
repositoryPost("/api/schedule/$id/delete")
repositoryPost("$prefix/api/schedule/$id/delete")
}
override suspend fun all(): List<Schedule> {
val json = repositoryGet("/api/schedules") ?: return emptyList()
val json = repositoryGet("$prefix/api/schedules") ?: return emptyList()
return parser.parse(json, Schedule.serializer().list)
}
@ -52,12 +54,12 @@ object ScheduleRepository : Repository<Schedule> {
}
suspend fun checkConstraints(): ConstraintMap {
val json = repositoryGet("/api/constraints")
val json = repositoryGet("$prefix/api/constraints")
return parser.parse(json, ConstraintMap.serializer())
}
suspend fun checkConstraintsFor(schedule: Schedule): ConstraintMap {
val json = repositoryGet("/api/constraint/${schedule.id}")
val json = repositoryGet("$prefix/api/constraint/${schedule.id}")
return parser.parse(json, ConstraintMap.serializer())
}
}

View file

@ -11,6 +11,8 @@ import kotlinx.serialization.list
object TrackRepository : Repository<Track> {
val prefix = js("prefix")
override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>()
@ -18,26 +20,26 @@ object TrackRepository : Repository<Track> {
private val parser = DynamicObjectParser()
override suspend fun get(id: Long): Track? {
val json = repositoryGet("/api/track/$id") ?: return null
val json = repositoryGet("$prefix/api/track/$id") ?: return null
return parser.parse(json, Track.serializer())
}
override suspend fun create(model: Track): Long {
return repositoryPost("/api/tracks", Message.json.stringify(Track.serializer(), model))
return repositoryPost("$prefix/api/tracks", Message.json.stringify(Track.serializer(), model))
?: throw IllegalStateException("Cannot create model!")
}
override suspend fun update(model: Track) {
if (model.id == null) throw IllegalStateException("Cannot update model which was not created!")
repositoryPost("/api/track/${model.id}", Message.json.stringify(Track.serializer(), model))
repositoryPost("$prefix/api/track/${model.id}", Message.json.stringify(Track.serializer(), model))
}
override suspend fun delete(id: Long) {
repositoryPost("/api/track/$id/delete")
repositoryPost("$prefix/api/track/$id/delete")
}
override suspend fun all(): List<Track> {
val json = repositoryGet("/api/tracks") ?: return emptyList()
val json = repositoryGet("$prefix/api/tracks") ?: return emptyList()
return parser.parse(json, Track.serializer().list)
}

View file

@ -11,6 +11,8 @@ import kotlinx.serialization.list
object UserRepository : Repository<User> {
val prefix = js("prefix")
override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>()
@ -18,26 +20,26 @@ object UserRepository : Repository<User> {
private val parser = DynamicObjectParser()
override suspend fun get(id: Long): User? {
val json = repositoryGet("/api/user/$id") ?: return null
val json = repositoryGet("$prefix/api/user/$id") ?: return null
return parser.parse(json, User.serializer())
}
override suspend fun create(model: User): Long {
return repositoryPost("/api/users", Message.json.stringify(User.serializer(), model))
return repositoryPost("$prefix/api/users", Message.json.stringify(User.serializer(), model))
?: throw IllegalStateException("Cannot create model!")
}
override suspend fun update(model: User) {
if (model.id == null) throw IllegalStateException("Cannot update model which was not created!")
repositoryPost("/api/user/${model.id}", Message.json.stringify(User.serializer(), model))
repositoryPost("$prefix/api/user/${model.id}", Message.json.stringify(User.serializer(), model))
}
override suspend fun delete(id: Long) {
repositoryPost("/api/user/$id/delete")
repositoryPost("$prefix/api/user/$id/delete")
}
override suspend fun all(): List<User> {
val json = repositoryGet("/api/users") ?: return emptyList()
val json = repositoryGet("$prefix/api/users") ?: return emptyList()
return parser.parse(json, User.serializer().list)
}

View file

@ -11,6 +11,8 @@ import kotlinx.serialization.list
object WorkGroupRepository : Repository<WorkGroup> {
val prefix = js("prefix")
override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>()
@ -18,26 +20,26 @@ object WorkGroupRepository : Repository<WorkGroup> {
private val parser = DynamicObjectParser()
override suspend fun get(id: Long): WorkGroup? {
val json = repositoryGet("/api/workgroup/$id") ?: return null
val json = repositoryGet("$prefix/api/workgroup/$id") ?: return null
return parser.parse(json, WorkGroup.serializer())
}
override suspend fun create(model: WorkGroup): Long {
return repositoryPost("/api/workgroups", Message.json.stringify(WorkGroup.serializer(), model))
return repositoryPost("$prefix/api/workgroups", Message.json.stringify(WorkGroup.serializer(), model))
?: throw IllegalStateException("Cannot create model!")
}
override suspend fun update(model: WorkGroup) {
if (model.id == null) throw IllegalStateException("Cannot update model which was not created!")
repositoryPost("/api/workgroup/${model.id}", Message.json.stringify(WorkGroup.serializer(), model))
repositoryPost("$prefix/api/workgroup/${model.id}", Message.json.stringify(WorkGroup.serializer(), model))
}
override suspend fun delete(id: Long) {
repositoryPost("/api/workgroup/$id/delete")
repositoryPost("$prefix/api/workgroup/$id/delete")
}
override suspend fun all(): List<WorkGroup> {
val json = repositoryGet("/api/workgroups") ?: return emptyList()
val json = repositoryGet("$prefix/api/workgroups") ?: return emptyList()
return parser.parse(json, WorkGroup.serializer().list)
}

View file

@ -47,6 +47,7 @@ fun initWorkGroupConstraints() {
html.name = "constraint-only-on-day-${index++}"
min = -1337.0
max = 1337.0
placeholder = "Tag"
}.html)
}.html)
}
@ -64,6 +65,7 @@ fun initWorkGroupConstraints() {
html.name = "constraint-not-on-day-${index++}"
min = -1337.0
max = 1337.0
placeholder = "Tag"
}.html)
}.html)
}
@ -78,13 +80,15 @@ fun initWorkGroupConstraints() {
}.html)
html.appendChild(InputView(InputType.TEXT).apply {
classList += "form-control"
html.name = "constraint-only-before-time-day-${index++}"
html.name = "constraint-only-before-time-day-${index}"
placeholder = "Tag (optional)"
}.html)
html.appendChild(InputView(InputType.NUMBER).apply {
classList += "form-control"
html.name = "constraint-only-before-time-${index++}"
min = -1337.0
max = 133700.0
placeholder = "Minuten"
}.html)
}.html)
}
@ -99,13 +103,15 @@ fun initWorkGroupConstraints() {
}.html)
html.appendChild(InputView(InputType.TEXT).apply {
classList += "form-control"
html.name = "constraint-only-after-time-day-${index++}"
html.name = "constraint-only-after-time-day-${index}"
placeholder = "Tag (optional)"
}.html)
html.appendChild(InputView(InputType.NUMBER).apply {
classList += "form-control"
html.name = "constraint-only-after-time-${index++}"
min = -1337.0
max = 133700.0
placeholder = "Minuten"
}.html)
}.html)
}

View file

@ -9,17 +9,20 @@ import de.westermann.kwebview.iterator
import org.w3c.dom.*
import kotlin.browser.document
import kotlin.browser.window
import kotlin.js.Date
class Calendar(calendar: HTMLElement) : View(calendar) {
var autoScroll = true
val day: Int = calendar.dataset["day"]?.toIntOrNull() ?: -1
val calendarTable = calendar.getElementsByClassName("calendar-table")[0] as HTMLElement
private val calendarTableHeader = calendar.getElementsByClassName("calendar-header")[0] as HTMLElement
val day = calendarTable.dataset["day"]?.toIntOrNull() ?: -1
val referenceDate = calendarTable.dataset["reference"]?.toLongOrNull() ?: -1L
val nowDate = calendarTable.dataset["now"]?.toLongOrNull() ?: -1L
val timeDifference = Date.now().toLong() - nowDate
fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
scrollAllVerticalBy(pixel, scrollBehavior)
}
@ -46,7 +49,6 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
Orientation.ROOM_TO_TIME
}
init {
scroll += calendarTable
@ -131,7 +133,6 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
private var scroll = listOf<HTMLElement>()
private fun scrollAllVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
println("scroll ${scroll.size} elemenets")
for (calendarTable in scroll) {
calendarTable.scrollBy(ScrollToOptions(0.0, pixel, scrollBehavior))
}

View file

@ -86,9 +86,14 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
}
fun update(scroll: ScrollBehavior) {
val currentTime = Date().let {
it.getHours() * 60 + it.getMinutes()
}
val now = Date.now().toLong() - calendar.timeDifference
val refDay = calendar.referenceDate / (1000 * 60 * 60 * 24)
val nowDay = now / (1000 * 60 * 60 * 24)
val d = nowDay - refDay
val diff = (day - d).toInt()
val date = Date(now)
val currentTime = date.getHours() * 60 + date.getMinutes() + (diff * 60 * 24)
val rowTime = (currentTime / 15) * 15
var activeRow: CalendarRow? = null
@ -116,7 +121,7 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
if (calendar.autoScroll && activeRow != null) {
if (calendar.orientation == Calendar.Orientation.ROOM_TO_TIME) {
calendar.scrollVerticalTo((activeRow.offsetTop).toDouble(), scroll)
calendar.scrollVerticalTo((activeRow.offsetTop - 150).toDouble(), scroll)
} else {
calendar.scrollHorizontalTo((activeRow.offsetLeft - 100).toDouble(), scroll)
}

View file

@ -7,10 +7,13 @@ import de.westermann.kwebview.iterator
import de.kif.frontend.launch
import de.kif.frontend.repository.RepositoryDelegate
import de.kif.frontend.repository.ScheduleRepository
import de.kif.frontend.views.overview.getByClassOrCreate
import de.westermann.kwebview.*
import de.westermann.kwebview.components.Body
import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLSpanElement
import org.w3c.dom.events.MouseEvent
import kotlin.browser.document
import kotlin.browser.window
import kotlin.dom.appendText
import kotlin.dom.isText
@ -19,6 +22,7 @@ import kotlin.js.Date
class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : View(view) {
private lateinit var mouseDelta: Point
private var ignoreEditHover = false
private var newCell: CalendarCell? = null
private var language by dataset.property("language")
@ -43,9 +47,20 @@ class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : Vie
private var moveLockRoom: Long? = null
private var moveLockTime: Int? = null
private val nameView = view.getByClassOrCreate<HTMLSpanElement>("calendar-entry-name")
private fun onMove(event: MouseEvent) {
val position = event.toPoint() - mouseDelta
if (ignoreEditHover) {
for (element in document.elementsFromPoint(position.x, position.y)) {
if (element.classList.contains("calendar-edit")) {
return
}
}
ignoreEditHover = false
}
val cell = calendar.calendarCells.find {
position in it.dimension
}
@ -245,13 +260,7 @@ class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : Vie
}
}
for (element in html.childNodes) {
if (element.isText) {
html.removeChild(element)
}
}
html.appendText(workGroup.name)
nameView.textContent = workGroup.name
}
companion object {
@ -268,6 +277,7 @@ class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : Vie
entry.load(workGroup)
entry.mouseDelta = Point.ZERO
entry.ignoreEditHover = true
entry.startDrag()
return entry

View file

@ -1,6 +1,10 @@
$border-radius: 0.2rem;
$transitionTime: 150ms;
$mainFont: 'Raleway', Roboto, Arial, sans-serif;
$menuFont: 'Bungee', 'Raleway', Roboto, Arial, sans-serif;
$headFont: 'Montserrat', 'Raleway', Roboto, Arial, sans-serif;
@mixin no-select() {
-webkit-touch-callout: none;
-webkit-user-select: none;

View file

@ -213,6 +213,8 @@
span:first-child {
color: var(--text-primary-color);
width: 6rem;
overflow: hidden;
text-overflow: ellipsis;
&:hover {
background-color: transparent;
@ -297,6 +299,13 @@
@include no-select()
}
.calendar-entry-name {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.calendar-table-box {
display: flex;
flex-wrap: nowrap;
@ -404,7 +413,7 @@
left: 6rem;
right: 0;
height: 1px;
border-bottom: solid 1px $primary-color;
border-bottom: solid 1px var(--primary-color);
}
&.calendar-now::after {
@ -414,8 +423,8 @@
left: 6rem;
transform: scale(1, 0.5) rotate(-45deg);
transform-origin: bottom;
border-bottom: solid 0.4rem $primary-color;
border-right: solid 0.4rem $primary-color;
border-bottom: solid 0.4rem var(--primary-color);
border-right: solid 0.4rem var(--primary-color);
border-top: solid 0.4rem transparent;
border-left: solid 0.4rem transparent;
margin-top: -0.55rem;
@ -498,7 +507,7 @@
top: 3rem;
bottom: 0;
width: 1px;
border-right: solid 1px $primary-color;
border-right: solid 1px var(--primary-color);
}
&.calendar-now::after {
@ -508,8 +517,8 @@
top: 3rem;
transform: scale(0.5, 1) rotate(45deg);
transform-origin: right;
border-bottom: solid 0.4rem $primary-color;
border-right: solid 0.4rem $primary-color;
border-bottom: solid 0.4rem var(--primary-color);
border-right: solid 0.4rem var(--primary-color);
border-top: solid 0.4rem transparent;
border-left: solid 0.4rem transparent;
margin-top: -0.3rem;

View file

@ -13,7 +13,7 @@
color: var(--text-primary-color);
height: 100%;
display: inline-block;
font-family: "Bungee", sans-serif;
font-family: $menuFont;
font-weight: normal;
font-size: 1.1rem;
position: relative;

View file

@ -33,7 +33,7 @@
line-height: 2rem;
padding: 0 1rem;
font-weight: bold;
font-family: 'Montserrat', sans-serif;
font-family: $headFont;
&:empty::before {
display: block;

View file

@ -39,6 +39,7 @@
margin-top: -0.5rem !important;
bottom: 0 !important;
}
.calendar-entry::after {
content: none;
}
@ -65,6 +66,12 @@
line-height: 2rem;
width: 100%;
}
.calendar-header {
.calendar-cell {
overflow: hidden;
}
}
}
.wall-calendar {

View file

@ -15,7 +15,7 @@ body, html {
color: var(--text-primary-color);
background: var(--background-secondary-color);
font-family: 'Raleway', 'Montserrat', Roboto, Arial, sans-serif;
font-family: $mainFont;
font-weight: 500;
width: 100%;
@ -30,6 +30,10 @@ body, html {
}
}
h1, h2, h3, h4, h5, h6 {
font-family: $headFont;
}
.no-select {
@include no-select()
}