From 5122630c7a05c515e89b16ab7bb4d892f1621185 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 26 Apr 2023 03:33:20 +0100 Subject: [PATCH] [MIRROR] Books now render Markdown, fixing paper importing [MDB IGNORE] (#20770) * Books now render Markdown, fixing paper importing (#74902) ## About The Pull Request Books didn't render markdown and instead just dumped the raw contents, (after a html encode), into the window. Changes them to use tgui and support markdown rendering. ## Why It's Good For The Game Books should should look the same as the paper used to make them. ## Changelog :cl: fix: Book's no longer take your formatting and throw it out the window. refactor: Book display and rendering /:cl: --------- Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@ users.noreply.github.com> Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com> * Books now render Markdown, fixing paper importing --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@ users.noreply.github.com> Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com> --- code/modules/fishing/fish_catalog.dm | 3 -- code/modules/library/book.dm | 41 +++++++++++------- code/modules/library/lib_machines.dm | 27 +++++++++++- .../tgui/interfaces/MarkdownViewer.tsx | 42 +++++++++++++++++++ 4 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/MarkdownViewer.tsx diff --git a/code/modules/fishing/fish_catalog.dm b/code/modules/fishing/fish_catalog.dm index 396d112bd43..854a4080b89 100644 --- a/code/modules/fishing/fish_catalog.dm +++ b/code/modules/fishing/fish_catalog.dm @@ -5,9 +5,6 @@ icon_state = "fishbook" starting_content = "Lot of fish stuff" //book wrappers could use cleaning so this is not necessary -/obj/item/book/fish_catalog/on_read(mob/user) - ui_interact(user) - /obj/item/book/fish_catalog/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm index 662d8417c68..cb7bd2063f8 100644 --- a/code/modules/library/book.dm +++ b/code/modules/library/book.dm @@ -46,9 +46,10 @@ var/raw_content = "" for(var/datum/paper_input/text_input as anything in paper.raw_text_inputs) - raw_content += text_input.raw_text - - // Content from paper is never trusted. It it raw, unsanitised, unparsed user input. + if(!isnull(text_input.colour)) + raw_content += text_input.raw_text + else + raw_content += "[text_input.raw_text]" content = trim(html_encode(raw_content), MAX_PAPER_LENGTH) /datum/book_info/proc/get_content(default="N/A") @@ -112,19 +113,29 @@ AddElement(/datum/element/falling_hazard, damage = 5, wound_bonus = 0, hardhat_safety = TRUE, crushes = FALSE, impact_sound = drop_sound) -/obj/item/book/proc/on_read(mob/living/user) - if(book_data?.content) - user << browse("Penned by [book_data.author].
" + "[book_data.content]", "window=book[window_size != null ? ";size=[window_size]" : ""]") +/obj/item/book/ui_static_data(mob/user) + var/list/data = list() + data["author"] = book_data.get_author() + data["title"] = book_data.get_title() + data["content"] = book_data.get_content() + return data - LAZYINITLIST(user.mind?.book_titles_read) - var/has_not_read_book = isnull(user.mind?.book_titles_read[starting_title]) +/obj/item/book/ui_interact(mob/living/user, datum/tgui/ui) + if(!length(book_data.get_content())) + balloon_alert(user, "this book is blank!") + return - if(has_not_read_book) // any new books give bonus mood + if(istype(user) && !isnull(user.mind)) + LAZYINITLIST(user.mind.book_titles_read) + var/has_not_read_book = !(starting_title in user.mind.book_titles_read) + if(has_not_read_book) user.add_mood_event("book_nerd", /datum/mood_event/book_nerd) - user.mind?.book_titles_read[starting_title] = TRUE - onclose(user, "book") - else - to_chat(user, span_notice("This book is completely blank!")) + user.mind.book_titles_read[starting_title] = TRUE + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "MarkdownViewer", name) + ui.open() /// Generates a random icon state for the book /obj/item/book/proc/gen_random_icon_state() @@ -134,10 +145,12 @@ if(user.is_blind()) to_chat(user, span_warning("You are blind and can't read anything!")) return + if(!user.can_read(src)) return + user.visible_message(span_notice("[user] opens a book titled \"[book_data.title]\" and begins reading intently.")) - on_read(user) + ui_interact(user) /obj/item/book/attackby(obj/item/attacking_item, mob/user, params) if(burn_paper_product_attackby_check(attacking_item, user)) diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index 60061fffcf1..c24fba1709c 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -776,8 +776,13 @@ icon_state = "binder" desc = "Only intended for binding paper products." density = TRUE + + /// Are we currently binding a book? var/busy = FALSE + /// Name of the author for the book, set by scanning your ID. + var/scanned_name + /obj/machinery/bookbinder/wrench_act(mob/living/user, obj/item/tool) . = ..() default_unfasten_wrench(user, tool) @@ -786,17 +791,32 @@ /obj/machinery/bookbinder/attackby(obj/hitby, mob/user, params) if(istype(hitby, /obj/item/paper)) prebind_book(user, hitby) - return + return TRUE + + if(isidcard(hitby)) + var/obj/item/card/id/idcard = hitby + scanned_name = idcard.registered_name + balloon_alert(user, "scanned") + return TRUE + return ..() /obj/machinery/bookbinder/proc/prebind_book(mob/user, obj/item/paper/draw_from) if(machine_stat) return + if(busy) to_chat(user, span_warning("The book binder is busy. Please wait for completion of previous operation.")) return + + if(!scanned_name) + scanned_name = "unknown author" + say("No ID detected. Please scan your ID if you would like to be credited for this book. Otherwise please enter your paper again.") + return + if(!user.transferItemToLoc(draw_from, src)) return + user.visible_message(span_notice("[user] loads some paper into [src]."), span_notice("You load some paper into [src].")) audible_message(span_hear("[src] begins to hum as it warms up its printing drums.")) busy = TRUE @@ -808,14 +828,19 @@ busy = FALSE if(!draw_from) //What the fuck did you do return + if(machine_stat) draw_from.forceMove(drop_location()) return + visible_message(span_notice("[src] whirs as it prints and binds a new book.")) var/obj/item/book/bound_book = new(loc) bound_book.book_data.set_content_using_paper(draw_from) + bound_book.book_data.set_author(scanned_name, trusted = FALSE) bound_book.name = "Print Job #" + "[rand(100, 999)]" bound_book.gen_random_icon_state() + scanned_name = null + qdel(draw_from) #undef BOOKS_PER_PAGE diff --git a/tgui/packages/tgui/interfaces/MarkdownViewer.tsx b/tgui/packages/tgui/interfaces/MarkdownViewer.tsx new file mode 100644 index 00000000000..7fc8df38597 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MarkdownViewer.tsx @@ -0,0 +1,42 @@ +import { marked } from 'marked'; +import { useBackend } from '../backend'; +import { Window } from '../layouts'; +import { sanitizeText } from '../sanitize'; + +type MarkdownViewerData = { + title: string; + content: string; + author: string; +}; + +export const MarkdownViewer = (_: any, context: any) => { + const { data } = useBackend(context); + return ( + + + + + + ); +}; + +type MarkdownRendererProps = { + content: string; + sanitize?: boolean; +}; + +export const MarkdownRenderer = (props: MarkdownRendererProps) => { + let { content, sanitize } = props; + + content = marked(content); + if (sanitize) { + content = sanitizeText(content, /* advHtml = */ false); + } + + // eslint-disable-next-line react/no-danger + return
; +}; + +MarkdownRenderer.defaultProps = { + sanitize: true, +};