package quill
Interactive notebook for OCaml data science
Install
Dune Dependency
Authors
Maintainers
Sources
raven-1.0.0.alpha0.tbz
sha256=a9a8a9787f8250337187bb7b21cb317c41bfd2ecf08bcfe0ab407c7b6660764d
sha512=fe13cf257c487e41efe2967be147d80fa94bac8996d3aab2b8fd16f0bbbd108c15e0e58c025ec9bf294d4a0d220ca2ba00c3b1b42fa2143f758c5f0ee4c15782
doc/src/quill.editor/view.ml.html
Source file view.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
open Quill_markdown open Update open Vdom let span ?key ?a l = elt "span" ?key ?a l let p ?key ?a l = elt "p" ?key ?a l let tabindex = int_attr "tabindex" (* Helper functions for inline rendering *) let get_segments (inline : inline) = match inline.inline_content with Seq rs -> rs | _ -> [ inline ] and inline_to_plain (inline : inline) = inline_content_to_plain inline.inline_content let rec wrap_run ~block (run : inline) = let focused = run.focused in match run.inline_content with | Run s -> let id = "run-" ^ string_of_int run.id in span ~key:id ~a:[ attr "id" id; attr "class" "inline-text" ] [ (if s = "" then elt "br" [] else text s) ] | Code_span s -> let id = "codespan-" ^ string_of_int run.id in elt "code" ~key:id ~a:[ attr "id" id ] [ span ~a:[ bool_prop "hidden" (not focused) ] [ text "`" ]; span ~a:[ attr "class" "inline-content inline-text" ] [ (if s = "" then elt "br" [] else text s) ]; span ~a:[ bool_prop "hidden" (not focused) ] [ text "`" ]; ] | Emph inner -> let id = "emph-" ^ string_of_int run.id in elt "em" ~key:id ~a:[ attr "id" id ] [ span ~a: [ bool_prop "hidden" (not focused); bool_prop "contenteditable" false; ] [ text "*" ]; fragment @@ render_inline_content ~block inner; span ~a: [ bool_prop "hidden" (not focused); bool_prop "contenteditable" false; ] [ text "*" ]; ] | Strong inner -> let id = "strong-" ^ string_of_int run.id in elt "strong" ~key:id ~a:[ attr "id" id ] [ span ~a: [ bool_prop "hidden" (not focused); bool_prop "contenteditable" false; ] [ text "**" ]; fragment @@ render_inline_content ~block inner; span ~a: [ bool_prop "hidden" (not focused); bool_prop "contenteditable" false; ] [ text "**" ]; ] | Seq inlines -> let id = "seq-" ^ string_of_int run.id in span ~key:id ~a:[ attr "id" id ] (List.map (wrap_run ~block) inlines) | Break typ -> ( let id = "break-" ^ string_of_int run.id in match typ with | `Hard -> span ~key:id ~a:[ attr "id" id ] [ text "\n" (* Hard breaks render as newlines *) ] | `Soft -> span ~key:id ~a:[ attr "id" id ] [ text " " (* Soft breaks render as a space *) ]) | Image { alt; src } -> let id = "image-" ^ string_of_int run.id in if focused then span ~key:id ~a:[ attr "id" id ] [ text ""; ] else let alt_text = inline_to_plain alt in elt "img" ~key:id ~a:[ attr "id" id; attr "src" src; attr "alt" alt_text ] [] | Link { text = text'; href } -> let id = "link-" ^ string_of_int run.id in if focused then span ~key:id ~a:[ attr "id" id ] [ text "["; fragment (render_inline_content ~block text'); text "]("; text href; text ")"; ] else elt "a" ~key:id ~a:[ attr "id" id; attr "href" href ] (render_inline_content ~block text') | Raw_html html -> let id = "rawhtml-" ^ string_of_int run.id in if focused then span ~key:id ~a:[ attr "id" id ] [ text html ] else (* Assuming Vdom supports raw HTML; adjust as needed *) span ~key:id ~a:[ attr "id" id; attr "dangerouslySetInnerHTML" html ] [] and render_inline_content ~block (inline : inline) = match inline.inline_content with | Seq items -> List.map (wrap_run ~block) items | _ -> [ wrap_run ~block inline ] let newline = span ~a:[ bool_prop "hidden" true ] [ text "\n" ] let with_newline el = fragment [ el; newline ] let paragraph block_id inline = let id = Printf.sprintf "block-%d" block_id in let children = render_inline_content ~block:block_id inline in p ~key:id ~a:[ attr "id" id ] children |> with_newline let heading block_id level inline = let id = Printf.sprintf "block-%d" block_id in let tag = Printf.sprintf "h%d" level in let segs = get_segments inline in let children = List.map (fun run -> wrap_run ~block:block_id run) segs in let pre = span ~a:[ bool_prop "hidden" (not inline.focused) ] [ text (String.make level '#' ^ " ") ] in elt tag ~key:id ~a:[ attr "id" id ] (pre :: children) |> with_newline let blank_line block_id = p ~key:(Printf.sprintf "block-%d" block_id) ~a: [ attr "id" (Printf.sprintf "block-%d" block_id); bool_prop "hidden" true; ] [ text "\n" ] let rec codeblock block_id content = let id = Printf.sprintf "block-%d" block_id in let code_id = Printf.sprintf "codeblock-%d" block_id in let code_el = elt "code" ~a:[ attr "id" code_id ] [ text content.code ] in let pre_node = (* Capture the <pre> node without the trailing newline wrapper *) elt "pre" ~key:id ~a:[ attr "id" id ] [ span ~a:[ bool_prop "hidden" true ] [ text "```\n" ]; code_el; span ~a:[ bool_prop "hidden" true ] [ text "\n```\n" ]; (* Ensure PRE block has trailing newline in source *) ] in match content.output with | None -> pre_node | Some output_block -> let output_id = Printf.sprintf "output-%d" block_id in let start_comment = span ~a:[ bool_prop "hidden" true ] [ text "<!-- quill=output_start -->\n" ] in let end_comment = span ~a:[ bool_prop "hidden" true ] [ text "<!-- quill=output_end -->\n" ] in let output_el = div ~key:output_id ~a: [ attr "id" output_id; attr "class" "execution-output"; bool_prop "contenteditable" false; ] [ block output_block.id output_block.content ] in fragment [ pre_node; start_comment; output_el; end_comment ] and blocks block_id blocks = let id = Printf.sprintf "block-%d" block_id in let children = List.map (fun b -> block b.id b.content) blocks in div ~key:id ~a:[ attr "id" id ] children and block_quote block_id blocks = let id = Printf.sprintf "block-%d" block_id in let children = List.map (fun b -> block b.id b.content) blocks in elt "blockquote" ~key:id ~a:[ attr "id" id ] children |> with_newline and thematic_break block_id = let id = Printf.sprintf "block-%d" block_id in elt "hr" ~key:id ~a:[ attr "id" id ] [] |> with_newline and list block_id list_type _spacing items = let id = Printf.sprintf "block-%d" block_id in let tag = match list_type with Unordered _ -> "ul" | Ordered _ -> "ol" in let list_items = List.mapi (fun i item_blocks -> let item_id = Printf.sprintf "%s-item-%d" id i in let children = List.map (fun b -> block b.id b.content) item_blocks in elt "li" ~key:item_id ~a:[ attr "id" item_id ] children) items in elt tag ~key:id ~a:[ attr "id" id ] list_items |> with_newline and html_block block_id html = let id = Printf.sprintf "block-%d" block_id in (* For safety, we render HTML blocks as text in the editor *) div ~key:id ~a:[ attr "id" id; attr "class" "html-block" ] [ elt "code" [ text html ] ] |> with_newline and link_reference_definition block_id _ld = (* Link reference definitions are not typically shown in the rendered output *) let id = Printf.sprintf "block-%d" block_id in div ~key:id ~a:[ attr "id" id; bool_prop "hidden" true ] [] and block block_id block_content = match block_content with | Paragraph inline -> paragraph block_id inline | Codeblock code -> codeblock block_id code | Heading (level, inline) -> heading block_id level inline | Blocks bs -> blocks block_id bs | Blank_line () -> blank_line block_id | Block_quote bs -> block_quote block_id bs | Thematic_break -> thematic_break block_id | List (list_type, spacing, items) -> list block_id list_type spacing items | Html_block html -> html_block block_id html | Link_reference_definition ld -> link_reference_definition block_id ld let view (model : Model.t) : msg Vdom.vdom = let editor_content = match model.document with | [] -> p [] | _ -> fragment (List.map (fun b -> block b.id b.content) model.document) in fragment [ div ~a:[ attr "id" "editor"; attr "contentEditable" "true" ] [ editor_content ]; div ~a:[ attr "id" "debug" ] [ View_debug.view model ]; ]
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>