diff --git a/api/formapi.js b/api/formapi.js index 89c385a..70d1b28 100644 --- a/api/formapi.js +++ b/api/formapi.js @@ -32,23 +32,19 @@ module.exports = [ if (params.has("referrer")) { return { statusCode: 303, - contentType: "application/json", + contentType: "text/plain", headers: Object.assign(responseHeaders, { Location: params.get("referrer") }), - content: { - status: "ok" - } + content: "Success, redirecting..." } return redirect(params.get("referrer"), 303) } else { return { statusCode: 200, - contentType: "application/json", + contentType: "text/plain", headers: responseHeaders, - content: { - status: "ok" - } + content: "Success." } } }) @@ -56,7 +52,27 @@ module.exports = [ } }, { - route: `/formapi/erase`, methods: ["POST"], upload: true, code: async ({req, fill, body}) => { + route: `/formapi/markwatched/(${constants.regex.video_id})`, methods: ["POST"], code: async ({req, fill}) => { + const videoID = fill[0] + const user = getUser(req) + const token = user.token + if (token) { + db.prepare("INSERT OR IGNORE INTO WatchedVideos (token, videoID) VALUES (?, ?)").run(token, videoID) + } + return { + statusCode: 303, + contentType: "text/plain", + headers: { + Location: "/subscriptions" + }, + content: { + status: "Success, redirecting..." + } + } + } + }, + { + route: "/formapi/erase", methods: ["POST"], upload: true, code: async ({req, fill, body}) => { return new V() .with(validate.presetLoad({body})) .with(validate.presetURLParamsBody()) @@ -69,13 +85,12 @@ module.exports = [ }) return { statusCode: 303, + contentType: "text/plain", headers: { location: "/", "set-cookie": `token=; Path=/; Max-Age=0; HttpOnly; SameSite=Lax` }, - content: { - status: "ok" - } + content: "Success, redirecting..." } }) .go() @@ -88,10 +103,8 @@ module.exports = [ headers: setToken({ location: "/subscriptions" }, fill[0]).responseHeaders, - contentType: "application/json", - content: { - status: "ok" - } + contentType: "text/plain", + content: "Success, redirecting..." } } } diff --git a/html/static/js/mark-watched.js b/html/static/js/mark-watched.js new file mode 100644 index 0000000..0f0f9a9 --- /dev/null +++ b/html/static/js/mark-watched.js @@ -0,0 +1,24 @@ +import {ElemJS} from "/static/js/elemjs/elemjs.js" + +class MarkWatchedButton extends ElemJS { + constructor(element) { + super(element) + this.on("click", this.onClick.bind(this)) + } + + onClick(event) { + event.preventDefault() + let video = this.element + while (!video.classList.contains("subscriptions-video")) { + video = video.parentElement + } + video.classList.add("video-list-item--watched") + const form = this.element.parentElement + fetch(form.getAttribute("action"), {method: "POST"}) + form.remove() + } +} + +export { + MarkWatchedButton +} diff --git a/html/static/js/subscriptions.js b/html/static/js/subscriptions.js new file mode 100644 index 0000000..f10fdb1 --- /dev/null +++ b/html/static/js/subscriptions.js @@ -0,0 +1,6 @@ +import {qa} from "/static/js/elemjs/elemjs.js" +import {MarkWatchedButton} from "/static/js/mark-watched.js" + +for (const button of qa(".mark-watched__button")) { + new MarkWatchedButton(button) +} diff --git a/pug/includes/video-list-item.pug b/pug/includes/video-list-item.pug index 2d1343a..4cd4b86 100644 --- a/pug/includes/video-list-item.pug +++ b/pug/includes/video-list-item.pug @@ -1,4 +1,4 @@ -mixin video_list_item(className, video, instanceOrigin) +mixin video_list_item(className, video, instanceOrigin, options = {}) div(class={[className]: true, "video-list-item--watched": video.watched}) - let link = `/watch?v=${video.videoId}` a(href=link tabindex="-1").thumbnail @@ -16,5 +16,9 @@ mixin video_list_item(className, video, instanceOrigin) if video.publishedText = ` • ` span.published= video.publishedText + if options.showMarkWatched + form(method="post" action=`/formapi/markwatched/${video.videoId}`).mark-watched + = ` • ` + button.mark-watched__button Mark watched if video.descriptionHtml div.description!= video.descriptionHtml diff --git a/pug/subscriptions.pug b/pug/subscriptions.pug index c497951..6cecdde 100644 --- a/pug/subscriptions.pug +++ b/pug/subscriptions.pug @@ -4,6 +4,7 @@ include includes/video-list-item.pug block head title Subscriptions - CloudTube + script(type="module" src=getStaticURL("html", "/static/js/subscriptions.js")) block content main.subscriptions-page @@ -34,7 +35,7 @@ block content label(for="watched-videos-display").watched-videos-display-label Hide watched videos each video in videos - +video_list_item("subscriptions-video", video, instanceOrigin) + +video_list_item("subscriptions-video", video, instanceOrigin, {showMarkWatched: settings.save_history && !video.watched}) else .no-subscriptions h2 You have no subscriptions. diff --git a/sass/includes/forms.sass b/sass/includes/forms.sass index 9426dd5..5f48a5f 100644 --- a/sass/includes/forms.sass +++ b/sass/includes/forms.sass @@ -101,3 +101,17 @@ fieldset .#{$base}-label padding: 12px 0px 12px 32px cursor: pointer + +@mixin single-button-form + display: inline-block + white-space: pre-wrap // preserve whitespace inside the form at the edge + + > button + background: none + padding: 0 + margin: 0 + border: none + color: inherit + font-family: inherit + font-size: inherit + text-decoration: underline diff --git a/sass/includes/subscriptions-page.sass b/sass/includes/subscriptions-page.sass index e10489d..46f4050 100644 --- a/sass/includes/subscriptions-page.sass +++ b/sass/includes/subscriptions-page.sass @@ -39,3 +39,6 @@ #watched-videos-display:checked ~ .video-list-item--watched display: none + +.mark-watched + @include forms.single-button-form