PBToolboxAI v4 ← Site

markdownview — u_pbt_markdownview #

← Component reference · Guide contents

markdownview shows a Markdown document, read-only, at the colours of the theme: headings, lists, tables, task lists, coloured code, pictures. You set the text in is_markdown, or the path of a file in is_source; a link never navigates, it raises ue_link_clicked and the application decides. The raw HTML of a document is never run.

▶ See it live — Demo application, Markdown viewer tile, with the code and this page side by side.


At a glance #

Userobjectu_pbt_markdownview
InputA Markdown text (is_markdown), or a file of the workstation or an https:// URL (is_source)
SyntaxCommonMark, plus GitHub's tables, task lists, strikethrough and bare links
Feedbackue_link_clicked for a link (the application decides), ue_loaded / ue_load_failed for a file, ue_search_result for the search
SafetyRaw HTML is shown as text; a javascript:, vbscript: or data: link is not clickable; an http:// picture is refused

Quick start #

// Show a Markdown file : its pictures and relative links are read against its folder
uo_md.is_source = "C:\Acme\Help\guide.md"

// ... or any text the application has
uo_md.is_markdown = "# Release notes~n~n- [x] Orders~n- [ ] Invoices"

// ue_link_clicked : the viewer never navigates, the application decides where to open as_url

Properties #

PropertyTypeDefaultDescription
is_markdownstring""The Markdown text to show. Setting it replaces the document (is_source then reads back empty); empty clears the view. The raw HTML it holds is displayed as text, never run. Reads back exactly as it was set
is_sourcestring""A Markdown file to show: a path of the workstation (.md, .markdown, .txt…), a file:/// address or an https:// URL. Its relative pictures and links are read against its folder. http:// is refused (REASON_INSECURE), as is any file that is not text (REASON_UNSUPPORTED); over 16 MB, REASON_TOO_LARGE. Setting it replaces the document (is_markdown then reads back empty); ue_loaded or ue_load_failed follows
ib_search_enabledbooleantrueCtrl+F in the document opens a search box — the same search as of_search: typing highlights, Enter or F3 next, Shift+Enter or Shift+F3 previous, Escape closes. false leaves the shortcut to an application that searches from its own box
ib_find_match_casebooleanfalseSearch option: finds only the text with the same case. The Aa toggle of the search box is the same switch. Read back live; of_reset puts it back to false
ib_find_whole_wordbooleanfalseSearch option: finds the text only as a whole word (pen is not found inside pencil). The ab toggle of the search box is the same switch. Read back live; of_reset puts it back to false
is_theme_stylestring""Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change
is_theme_modestring""Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change
il_theme_accentlong-1Accent colour of this component (-1 = the application accent, or the theme's)
is_tooltipstring""Simple tooltip shown when hovering the component
is_super_tooltip_titlestring""Title of the rich tooltip (takes precedence over is_tooltip)
is_super_tooltip_textstring""Text of the rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of the rich tooltip

Methods #

MethodDescription
of_clear ( ) → longEmpties the view: is_markdown and is_source read back empty; ib_search_enabled and the search options keep their values (of_reset is the one that puts every property back). Returns 0, -2 when the component is not created
of_refresh ( ) → longReads is_source again (from the disk or the network): the way to show a file rewritten at the same path; ue_loaded or ue_load_failed follows. Returns 0, -5 when no document is shown, -2 when the component is not created
of_search ( string as_query ) → longHighlights every occurrence (whatever the case by default — see ib_find_match_case —, as a whole word with ib_find_whole_word) and jumps to the first; an occurrence may cross a bold or a link. ue_search_result says how many. An empty query is of_clear_search. The search box opens with the query in it; with ib_search_enabled false, the document only highlights. Returns 0, -2 when the component is not created
of_search_next ( ) → longMoves to the NEXT occurrence (back to the first after the last); ue_search_result gives the new position. Returns 0, -2 when the component is not created
of_search_prev ( ) → longMoves to the PREVIOUS occurrence (back to the last before the first); ue_search_result gives the new position. Returns 0, -2 when the component is not created
of_clear_search ( ) → longDrops the search: no more highlight nor current occurrence (of_match_count returns 0), the search box closes. Returns 0, -2 when the component is not created
of_match_count ( ) → longReturns how many occurrences the current search found, read LIVE — the 12 of a 3 / 12 status line. 0 without a search
of_match_index ( ) → longReturns the 1-based position of the current occurrence, read LIVE — the 3 of a 3 / 12 status line. 0 without an occurrence
of_toc ( ref string as_titles[], ref long al_levels[], ref string as_anchors[] ) → longThe table of contents, read LIVE: one entry per heading, in order — its text, its level (1 to 6) and its anchor (what of_scroll_to and a #anchor link take, GitHub style: “Release checklist” gives release-checklist). The arrays are emptied first. Returns the number of headings, 0 for a document without any
of_scroll_to ( string as_anchor ) → longBrings the heading as_anchor to the top of the view: its anchor as of_toc gives it, with or without #, or its text. Returns 0, -5 when no heading matches, -2 when the component is not created

Events #

EventWhen
ue_link_clicked (string as_url)The user followed a link (a click, or Enter on a focused link). The component does NOT navigate: open as_url where you want. A relative link of a file shown by is_source arrives resolved against its folder; a #heading link scrolls by itself and is not raised; a javascript: or data: link is not even clickable
ue_loaded (string as_source)The document is on screen: as_source is is_source as you wrote it, or an empty string for a text set by is_markdown
ue_load_failed (string as_source, string as_reason)is_source could not be shown: as_reason is one of the REASON_* constants — REASON_NOT_FOUND (no such file), REASON_TOO_LARGE (over 16 MB), REASON_INSECURE (http://), REASON_UNSUPPORTED (not a text file, or another scheme), REASON_FAILED (a read or network error). ue_loaded is not raised
ue_search_result (long al_count, long al_index)A search ran or moved: al_count occurrences in all, the current one is al_index (1-based, 0 when none) — the makings of “3 / 12”

Example #

// ue_link_clicked of uo_md : the viewer never navigates, the application decides
if Lower(Right(as_url, 3)) = ".md" and FileExists(as_url) then
	uo_md.is_source = as_url                        // another page of the help
else
	ShellExecuteW(0, "open", as_url, "", "", 1)     // a web page, a mail
end if

Editing Markdown: a codeeditor and a markdownview #

// The editor colours Markdown ; the viewer shows the page
uo_editor.is_syntax = u_pbt_codeeditor.SYNTAX_MARKDOWN
uo_editor.is_text = ls_notes
uo_md.is_markdown = ls_notes

// ue_changed of uo_editor : the whole recipe
uo_md.is_markdown = uo_editor.is_text

A table of contents in a list #

// Local variables
string ls_titles[], ls_anchors[]
long ll_levels[], ll_i

// One line per heading, indented by its level
for ll_i = 1 to uo_md.of_toc(/*titles*/ ls_titles, /*levels*/ ll_levels, /*anchors*/ ls_anchors)
	lb_toc.AddItem(Fill(" ", (ll_levels[ll_i] - 1) * 3) + ls_titles[ll_i])
next

// SelectionChanged of lb_toc : bring that heading to the top
uo_md.of_scroll_to(/*anchor*/ ls_anchors[index])

Good practice #


Inherited from the common base #

These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.

MembersRoleDetailed in
of_resetPut the component back to zero3.6 Resetting a component: of_reset()
of_register_shortcut · of_clear_shortcutsThe component's keyboard chords3.5 Keyboard shortcuts
of_is_created · of_is_ready · of_get_last_errorWhether it was born, whether it is ready, what failed3.7 Diagnostics
of_save_as_png · of_save_as_jpgExport the rendering as an image3.8 Exporting the rendering as an image
of_set_redrawGroup changes into a single repaint3.10 Best practices
of_preload_iconsIcons shown with no delayInstant display: of_icon
of_set_translationTranslate one of the component's labels5.2 Adapting a label: of_set_translation
of_focus_webviewGive the component the focus6.4 Keyboard and focus
of_print · of_print_to_pdfPrint, or write a PDF6.9 Printing
of_set_property · of_get_property · of_component_nameDriving a property by its name3.1 The property engine

← Component reference · Guide contents