html-to-markdown 3.4.0 → 3.6.0.pre.rc.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +347 -0
- data/Steepfile +10 -2
- data/ext/html_to_markdown_rb/Cargo.toml +3 -2
- data/ext/html_to_markdown_rb/extconf.rb +5 -5
- data/ext/html_to_markdown_rb/native/Cargo.lock +962 -0
- data/ext/html_to_markdown_rb/native/Cargo.toml +6 -11
- data/ext/html_to_markdown_rb/native/extconf.rb +14 -0
- data/ext/html_to_markdown_rb/src/lib.rs +1715 -646
- data/lib/html_to_markdown/native.rb +913 -37
- data/lib/html_to_markdown/version.rb +3 -3
- data/lib/html_to_markdown.rb +9 -4
- data/lib/html_to_markdown_rb.so +0 -0
- data/sig/types.rbs +59 -292
- metadata +32 -179
- data/ext/html_to_markdown_rb/Makefile +0 -592
- data/lib/bin/html-to-markdown +0 -0
- data/vendor/Cargo.toml +0 -33
- data/vendor/html-to-markdown-rs/Cargo.toml +0 -54
- data/vendor/html-to-markdown-rs/README.md +0 -278
- data/vendor/html-to-markdown-rs/examples/basic.rs +0 -24
- data/vendor/html-to-markdown-rs/examples/table.rs +0 -25
- data/vendor/html-to-markdown-rs/examples/test_deser.rs +0 -12
- data/vendor/html-to-markdown-rs/examples/test_escape.rs +0 -58
- data/vendor/html-to-markdown-rs/examples/test_inline_formatting.rs +0 -113
- data/vendor/html-to-markdown-rs/examples/test_lists.rs +0 -39
- data/vendor/html-to-markdown-rs/examples/test_semantic_tags.rs +0 -89
- data/vendor/html-to-markdown-rs/examples/test_tables.rs +0 -100
- data/vendor/html-to-markdown-rs/examples/test_task_lists.rs +0 -61
- data/vendor/html-to-markdown-rs/examples/test_whitespace.rs +0 -34
- data/vendor/html-to-markdown-rs/src/convert_api.rs +0 -349
- data/vendor/html-to-markdown-rs/src/converter/block/blockquote.rs +0 -178
- data/vendor/html-to-markdown-rs/src/converter/block/container.rs +0 -114
- data/vendor/html-to-markdown-rs/src/converter/block/div.rs +0 -149
- data/vendor/html-to-markdown-rs/src/converter/block/heading.rs +0 -428
- data/vendor/html-to-markdown-rs/src/converter/block/horizontal_rule.rs +0 -103
- data/vendor/html-to-markdown-rs/src/converter/block/line_break.rs +0 -89
- data/vendor/html-to-markdown-rs/src/converter/block/mod.rs +0 -10
- data/vendor/html-to-markdown-rs/src/converter/block/paragraph.rs +0 -140
- data/vendor/html-to-markdown-rs/src/converter/block/preformatted.rs +0 -298
- data/vendor/html-to-markdown-rs/src/converter/block/table/builder.rs +0 -453
- data/vendor/html-to-markdown-rs/src/converter/block/table/caption.rs +0 -44
- data/vendor/html-to-markdown-rs/src/converter/block/table/cell.rs +0 -276
- data/vendor/html-to-markdown-rs/src/converter/block/table/cells.rs +0 -336
- data/vendor/html-to-markdown-rs/src/converter/block/table/layout.rs +0 -58
- data/vendor/html-to-markdown-rs/src/converter/block/table/mod.rs +0 -266
- data/vendor/html-to-markdown-rs/src/converter/block/table/scanner.rs +0 -146
- data/vendor/html-to-markdown-rs/src/converter/block/table/utils.rs +0 -34
- data/vendor/html-to-markdown-rs/src/converter/block/unknown.rs +0 -138
- data/vendor/html-to-markdown-rs/src/converter/context.rs +0 -208
- data/vendor/html-to-markdown-rs/src/converter/dom_context.rs +0 -337
- data/vendor/html-to-markdown-rs/src/converter/form/elements.rs +0 -770
- data/vendor/html-to-markdown-rs/src/converter/form/mod.rs +0 -82
- data/vendor/html-to-markdown-rs/src/converter/format/djot.rs +0 -64
- data/vendor/html-to-markdown-rs/src/converter/format/markdown.rs +0 -59
- data/vendor/html-to-markdown-rs/src/converter/format/mod.rs +0 -43
- data/vendor/html-to-markdown-rs/src/converter/handlers/blockquote.rs +0 -173
- data/vendor/html-to-markdown-rs/src/converter/handlers/code_block.rs +0 -434
- data/vendor/html-to-markdown-rs/src/converter/handlers/graphic.rs +0 -234
- data/vendor/html-to-markdown-rs/src/converter/handlers/image.rs +0 -282
- data/vendor/html-to-markdown-rs/src/converter/handlers/link.rs +0 -316
- data/vendor/html-to-markdown-rs/src/converter/handlers/mod.rs +0 -26
- data/vendor/html-to-markdown-rs/src/converter/inline/code.rs +0 -306
- data/vendor/html-to-markdown-rs/src/converter/inline/emphasis.rs +0 -345
- data/vendor/html-to-markdown-rs/src/converter/inline/link.rs +0 -428
- data/vendor/html-to-markdown-rs/src/converter/inline/mod.rs +0 -237
- data/vendor/html-to-markdown-rs/src/converter/inline/ruby.rs +0 -337
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/marks.rs +0 -566
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/mod.rs +0 -86
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/typography.rs +0 -558
- data/vendor/html-to-markdown-rs/src/converter/list/definition.rs +0 -232
- data/vendor/html-to-markdown-rs/src/converter/list/item.rs +0 -332
- data/vendor/html-to-markdown-rs/src/converter/list/mod.rs +0 -70
- data/vendor/html-to-markdown-rs/src/converter/list/ordered.rs +0 -201
- data/vendor/html-to-markdown-rs/src/converter/list/unordered.rs +0 -195
- data/vendor/html-to-markdown-rs/src/converter/list/utils.rs +0 -314
- data/vendor/html-to-markdown-rs/src/converter/main.rs +0 -710
- data/vendor/html-to-markdown-rs/src/converter/main_helpers.rs +0 -452
- data/vendor/html-to-markdown-rs/src/converter/media/embedded.rs +0 -393
- data/vendor/html-to-markdown-rs/src/converter/media/graphic.rs +0 -4
- data/vendor/html-to-markdown-rs/src/converter/media/image.rs +0 -183
- data/vendor/html-to-markdown-rs/src/converter/media/mod.rs +0 -87
- data/vendor/html-to-markdown-rs/src/converter/media/svg.rs +0 -280
- data/vendor/html-to-markdown-rs/src/converter/metadata.rs +0 -220
- data/vendor/html-to-markdown-rs/src/converter/mod.rs +0 -156
- data/vendor/html-to-markdown-rs/src/converter/plain_text.rs +0 -516
- data/vendor/html-to-markdown-rs/src/converter/preprocessing_helpers.rs +0 -201
- data/vendor/html-to-markdown-rs/src/converter/reference_collector.rs +0 -69
- data/vendor/html-to-markdown-rs/src/converter/semantic/attributes.rs +0 -269
- data/vendor/html-to-markdown-rs/src/converter/semantic/definition_list.rs +0 -266
- data/vendor/html-to-markdown-rs/src/converter/semantic/figure.rs +0 -391
- data/vendor/html-to-markdown-rs/src/converter/semantic/mod.rs +0 -112
- data/vendor/html-to-markdown-rs/src/converter/semantic/sectioning.rs +0 -85
- data/vendor/html-to-markdown-rs/src/converter/semantic/summary.rs +0 -324
- data/vendor/html-to-markdown-rs/src/converter/text/mod.rs +0 -8
- data/vendor/html-to-markdown-rs/src/converter/text/processing.rs +0 -56
- data/vendor/html-to-markdown-rs/src/converter/text_node.rs +0 -269
- data/vendor/html-to-markdown-rs/src/converter/utility/attributes.rs +0 -151
- data/vendor/html-to-markdown-rs/src/converter/utility/caching.rs +0 -74
- data/vendor/html-to-markdown-rs/src/converter/utility/content.rs +0 -271
- data/vendor/html-to-markdown-rs/src/converter/utility/mod.rs +0 -17
- data/vendor/html-to-markdown-rs/src/converter/utility/preprocessing.rs +0 -1002
- data/vendor/html-to-markdown-rs/src/converter/utility/serialization.rs +0 -126
- data/vendor/html-to-markdown-rs/src/converter/utility/siblings.rs +0 -97
- data/vendor/html-to-markdown-rs/src/converter/visitor_hooks.rs +0 -189
- data/vendor/html-to-markdown-rs/src/error.rs +0 -43
- data/vendor/html-to-markdown-rs/src/exports.rs +0 -24
- data/vendor/html-to-markdown-rs/src/inline_images.rs +0 -336
- data/vendor/html-to-markdown-rs/src/lib.rs +0 -139
- data/vendor/html-to-markdown-rs/src/metadata/collector.rs +0 -457
- data/vendor/html-to-markdown-rs/src/metadata/config.rs +0 -394
- data/vendor/html-to-markdown-rs/src/metadata/extraction.rs +0 -398
- data/vendor/html-to-markdown-rs/src/metadata/mod.rs +0 -288
- data/vendor/html-to-markdown-rs/src/metadata/types.rs +0 -477
- data/vendor/html-to-markdown-rs/src/options/conversion.rs +0 -559
- data/vendor/html-to-markdown-rs/src/options/inline_image.rs +0 -111
- data/vendor/html-to-markdown-rs/src/options/mod.rs +0 -20
- data/vendor/html-to-markdown-rs/src/options/preprocessing.rs +0 -201
- data/vendor/html-to-markdown-rs/src/options/validation.rs +0 -416
- data/vendor/html-to-markdown-rs/src/prelude.rs +0 -1
- data/vendor/html-to-markdown-rs/src/rcdom.rs +0 -487
- data/vendor/html-to-markdown-rs/src/text.rs +0 -358
- data/vendor/html-to-markdown-rs/src/types/document.rs +0 -191
- data/vendor/html-to-markdown-rs/src/types/mod.rs +0 -17
- data/vendor/html-to-markdown-rs/src/types/result.rs +0 -54
- data/vendor/html-to-markdown-rs/src/types/structure_builder.rs +0 -791
- data/vendor/html-to-markdown-rs/src/types/structure_collector.rs +0 -483
- data/vendor/html-to-markdown-rs/src/types/tables.rs +0 -52
- data/vendor/html-to-markdown-rs/src/types/warnings.rs +0 -33
- data/vendor/html-to-markdown-rs/src/validation.rs +0 -158
- data/vendor/html-to-markdown-rs/src/visitor/default_impl.rs +0 -63
- data/vendor/html-to-markdown-rs/src/visitor/mod.rs +0 -41
- data/vendor/html-to-markdown-rs/src/visitor/traits.rs +0 -370
- data/vendor/html-to-markdown-rs/src/visitor/types.rs +0 -319
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/callbacks/mod.rs +0 -1
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/content.rs +0 -126
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/mod.rs +0 -27
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/state.rs +0 -110
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/traversal.rs +0 -250
- data/vendor/html-to-markdown-rs/src/visitor_helpers.rs +0 -597
- data/vendor/html-to-markdown-rs/src/wrapper/sync.rs +0 -413
- data/vendor/html-to-markdown-rs/src/wrapper/utils.rs +0 -290
- data/vendor/html-to-markdown-rs/src/wrapper.rs +0 -9
- data/vendor/html-to-markdown-rs/tests/br_in_inline_test.rs +0 -87
- data/vendor/html-to-markdown-rs/tests/commonmark_compliance_test.rs +0 -297
- data/vendor/html-to-markdown-rs/tests/djot_output_test.rs +0 -153
- data/vendor/html-to-markdown-rs/tests/exclude_selectors_test.rs +0 -132
- data/vendor/html-to-markdown-rs/tests/integration_test.rs +0 -631
- data/vendor/html-to-markdown-rs/tests/issue_121_regressions.rs +0 -49
- data/vendor/html-to-markdown-rs/tests/issue_127_regressions.rs +0 -58
- data/vendor/html-to-markdown-rs/tests/issue_128_regressions.rs +0 -17
- data/vendor/html-to-markdown-rs/tests/issue_131_regressions.rs +0 -41
- data/vendor/html-to-markdown-rs/tests/issue_134_regressions.rs +0 -40
- data/vendor/html-to-markdown-rs/tests/issue_139_regressions.rs +0 -26
- data/vendor/html-to-markdown-rs/tests/issue_140_regressions.rs +0 -185
- data/vendor/html-to-markdown-rs/tests/issue_143_regressions.rs +0 -100
- data/vendor/html-to-markdown-rs/tests/issue_145_regressions.rs +0 -133
- data/vendor/html-to-markdown-rs/tests/issue_146_regressions.rs +0 -144
- data/vendor/html-to-markdown-rs/tests/issue_176_regressions.rs +0 -62
- data/vendor/html-to-markdown-rs/tests/issue_190_regressions.rs +0 -128
- data/vendor/html-to-markdown-rs/tests/issue_199_regressions.rs +0 -20
- data/vendor/html-to-markdown-rs/tests/issue_200_regressions.rs +0 -62
- data/vendor/html-to-markdown-rs/tests/issue_212_regressions.rs +0 -68
- data/vendor/html-to-markdown-rs/tests/issue_216_217_regressions.rs +0 -87
- data/vendor/html-to-markdown-rs/tests/issue_336_regressions.rs +0 -74
- data/vendor/html-to-markdown-rs/tests/issue_339_regressions.rs +0 -92
- data/vendor/html-to-markdown-rs/tests/issue_347_regressions.rs +0 -154
- data/vendor/html-to-markdown-rs/tests/issue_348_visitor_plain.rs +0 -93
- data/vendor/html-to-markdown-rs/tests/json_ld_script_extraction.rs +0 -44
- data/vendor/html-to-markdown-rs/tests/lists_test.rs +0 -199
- data/vendor/html-to-markdown-rs/tests/plain_output_test.rs +0 -273
- data/vendor/html-to-markdown-rs/tests/preprocessing_tests.rs +0 -61
- data/vendor/html-to-markdown-rs/tests/reference_links_test.rs +0 -169
- data/vendor/html-to-markdown-rs/tests/sectioning_elements_test.rs +0 -137
- data/vendor/html-to-markdown-rs/tests/skip_images_test.rs +0 -522
- data/vendor/html-to-markdown-rs/tests/tables_test.rs +0 -743
- data/vendor/html-to-markdown-rs/tests/test_custom_elements.rs +0 -41
- data/vendor/html-to-markdown-rs/tests/test_issue_187.rs +0 -204
- data/vendor/html-to-markdown-rs/tests/test_issue_218.rs +0 -68
- data/vendor/html-to-markdown-rs/tests/test_issue_277.rs +0 -77
- data/vendor/html-to-markdown-rs/tests/test_max_depth.rs +0 -82
- data/vendor/html-to-markdown-rs/tests/test_nested_simple.rs +0 -45
- data/vendor/html-to-markdown-rs/tests/test_script_style_stripping.rs +0 -396
- data/vendor/html-to-markdown-rs/tests/test_spa_bisect.rs +0 -34
- data/vendor/html-to-markdown-rs/tests/visitor_code_integration_test.rs +0 -121
- data/vendor/html-to-markdown-rs/tests/visitor_integration_test.rs +0 -1190
- data/vendor/html-to-markdown-rs/tests/xml_tables_test.rs +0 -372
|
@@ -1,770 +0,0 @@
|
|
|
1
|
-
//! Handlers for HTML form elements.
|
|
2
|
-
//!
|
|
3
|
-
//! This module provides comprehensive handling for all HTML form-related elements,
|
|
4
|
-
//! including form containers, input controls, and measurement elements.
|
|
5
|
-
//!
|
|
6
|
-
//! Processed elements:
|
|
7
|
-
//! - **Form containers**: `<form>`, `<fieldset>`, `<legend>`, `<label>`
|
|
8
|
-
//! - **Text inputs**: `<input>`, `<textarea>`, `<button>`
|
|
9
|
-
//! - **Select controls**: `<select>`, `<option>`, `<optgroup>`
|
|
10
|
-
//! - **Measurement**: `<progress>`, `<meter>`, `<output>`, `<datalist>`
|
|
11
|
-
//!
|
|
12
|
-
//! In Markdown, forms are typically not fully representable, so the handlers
|
|
13
|
-
//! extract and format the content in a readable manner.
|
|
14
|
-
|
|
15
|
-
// Note: Context and DomContext are defined in converter.rs
|
|
16
|
-
// walk_node is also defined there and must be called via the parent module
|
|
17
|
-
use super::walk_node;
|
|
18
|
-
use std::borrow::Cow;
|
|
19
|
-
|
|
20
|
-
/// Handles the `<form>` element.
|
|
21
|
-
///
|
|
22
|
-
/// A form element is a container for form controls. In Markdown, it's rendered
|
|
23
|
-
/// as a block container with its content visible.
|
|
24
|
-
///
|
|
25
|
-
/// # Behavior
|
|
26
|
-
///
|
|
27
|
-
/// - **Inline mode**: Children are processed inline without block spacing
|
|
28
|
-
/// - **Block mode**: Content is collected, trimmed, and wrapped with blank lines
|
|
29
|
-
/// - **Empty content**: Skipped entirely
|
|
30
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
31
|
-
pub fn handle_form(
|
|
32
|
-
_tag_name: &str,
|
|
33
|
-
node_handle: &tl::NodeHandle,
|
|
34
|
-
parser: &tl::Parser,
|
|
35
|
-
output: &mut String,
|
|
36
|
-
options: &crate::options::ConversionOptions,
|
|
37
|
-
ctx: &super::Context,
|
|
38
|
-
depth: usize,
|
|
39
|
-
dom_ctx: &super::DomContext,
|
|
40
|
-
) {
|
|
41
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
42
|
-
#[cfg(feature = "visitor")]
|
|
43
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
44
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
45
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
46
|
-
|
|
47
|
-
let attributes = collect_tag_attributes(tag);
|
|
48
|
-
let node_id = node_handle.get_inner();
|
|
49
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
50
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
51
|
-
let action = tag
|
|
52
|
-
.attributes()
|
|
53
|
-
.get("action")
|
|
54
|
-
.flatten()
|
|
55
|
-
.map(|v| v.as_utf8_str().into_owned());
|
|
56
|
-
let method = tag
|
|
57
|
-
.attributes()
|
|
58
|
-
.get("method")
|
|
59
|
-
.flatten()
|
|
60
|
-
.map(|v| v.as_utf8_str().into_owned());
|
|
61
|
-
let node_ctx = NodeContext {
|
|
62
|
-
node_type: NodeType::Form,
|
|
63
|
-
tag_name: "form".to_string(),
|
|
64
|
-
attributes,
|
|
65
|
-
depth,
|
|
66
|
-
index_in_parent,
|
|
67
|
-
parent_tag,
|
|
68
|
-
is_inline: false,
|
|
69
|
-
};
|
|
70
|
-
let visit_result = {
|
|
71
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
72
|
-
visitor.visit_form(&node_ctx, action.as_deref(), method.as_deref())
|
|
73
|
-
};
|
|
74
|
-
match visit_result {
|
|
75
|
-
VisitResult::Continue => {}
|
|
76
|
-
VisitResult::Skip => return,
|
|
77
|
-
VisitResult::Custom(custom) => {
|
|
78
|
-
if !output.is_empty() && !output.ends_with("\n\n") {
|
|
79
|
-
output.push_str("\n\n");
|
|
80
|
-
}
|
|
81
|
-
output.push_str(&custom);
|
|
82
|
-
output.push_str("\n\n");
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
VisitResult::PreserveHtml => {
|
|
86
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
87
|
-
output.push_str(&serialize_node(node_handle, parser));
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
VisitResult::Error(err) => {
|
|
91
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
92
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
93
|
-
}
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// In inline context, just process children inline
|
|
100
|
-
if ctx.convert_as_inline {
|
|
101
|
-
let children = tag.children();
|
|
102
|
-
{
|
|
103
|
-
for child_handle in children.top().iter() {
|
|
104
|
-
super::walk_node(child_handle, parser, output, options, ctx, depth, dom_ctx);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Collect content
|
|
111
|
-
let mut content = String::new();
|
|
112
|
-
let children = tag.children();
|
|
113
|
-
{
|
|
114
|
-
for child_handle in children.top().iter() {
|
|
115
|
-
walk_node(child_handle, parser, &mut content, options, ctx, depth, dom_ctx);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
let trimmed = content.trim();
|
|
120
|
-
if !trimmed.is_empty() {
|
|
121
|
-
// Add spacing before if needed
|
|
122
|
-
if !output.is_empty() && !output.ends_with("\n\n") {
|
|
123
|
-
output.push_str("\n\n");
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Output content
|
|
127
|
-
output.push_str(trimmed);
|
|
128
|
-
output.push_str("\n\n");
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/// Handles the `<fieldset>` element.
|
|
134
|
-
///
|
|
135
|
-
/// A fieldset element groups form controls with an optional legend.
|
|
136
|
-
/// In Markdown, it's rendered as a block container.
|
|
137
|
-
///
|
|
138
|
-
/// # Behavior
|
|
139
|
-
///
|
|
140
|
-
/// - **Inline mode**: Children are processed inline without block spacing
|
|
141
|
-
/// - **Block mode**: Content is collected, trimmed, and wrapped with blank lines
|
|
142
|
-
/// - **Empty content**: Skipped entirely
|
|
143
|
-
pub fn handle_fieldset(
|
|
144
|
-
_tag_name: &str,
|
|
145
|
-
node_handle: &tl::NodeHandle,
|
|
146
|
-
parser: &tl::Parser,
|
|
147
|
-
output: &mut String,
|
|
148
|
-
options: &crate::options::ConversionOptions,
|
|
149
|
-
ctx: &super::Context,
|
|
150
|
-
depth: usize,
|
|
151
|
-
dom_ctx: &super::DomContext,
|
|
152
|
-
) {
|
|
153
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
154
|
-
// In inline context, just process children inline
|
|
155
|
-
if ctx.convert_as_inline {
|
|
156
|
-
let children = tag.children();
|
|
157
|
-
{
|
|
158
|
-
for child_handle in children.top().iter() {
|
|
159
|
-
super::walk_node(child_handle, parser, output, options, ctx, depth, dom_ctx);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Collect content
|
|
166
|
-
let mut content = String::new();
|
|
167
|
-
let children = tag.children();
|
|
168
|
-
{
|
|
169
|
-
for child_handle in children.top().iter() {
|
|
170
|
-
walk_node(child_handle, parser, &mut content, options, ctx, depth, dom_ctx);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
let trimmed = content.trim();
|
|
175
|
-
if !trimmed.is_empty() {
|
|
176
|
-
// Add spacing before if needed
|
|
177
|
-
if !output.is_empty() && !output.ends_with("\n\n") {
|
|
178
|
-
output.push_str("\n\n");
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Output content
|
|
182
|
-
output.push_str(trimmed);
|
|
183
|
-
output.push_str("\n\n");
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/// Handles the `<legend>` element.
|
|
189
|
-
///
|
|
190
|
-
/// A legend element provides a caption for a fieldset. It's rendered as
|
|
191
|
-
/// strong (bold) text to distinguish it from regular content.
|
|
192
|
-
///
|
|
193
|
-
/// # Behavior
|
|
194
|
-
///
|
|
195
|
-
/// - **Block mode**: Content is wrapped in strong markers (e.g., `**text**`)
|
|
196
|
-
/// - **Inline mode**: Content is rendered without emphasis
|
|
197
|
-
/// - Uses the configured strong/emphasis symbol from ConversionOptions
|
|
198
|
-
pub fn handle_legend(
|
|
199
|
-
_tag_name: &str,
|
|
200
|
-
node_handle: &tl::NodeHandle,
|
|
201
|
-
parser: &tl::Parser,
|
|
202
|
-
output: &mut String,
|
|
203
|
-
options: &crate::options::ConversionOptions,
|
|
204
|
-
ctx: &super::Context,
|
|
205
|
-
depth: usize,
|
|
206
|
-
dom_ctx: &super::DomContext,
|
|
207
|
-
) {
|
|
208
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
209
|
-
let mut content = String::new();
|
|
210
|
-
|
|
211
|
-
// Set strong context for nested content
|
|
212
|
-
let mut legend_ctx = ctx.clone();
|
|
213
|
-
if !ctx.convert_as_inline {
|
|
214
|
-
legend_ctx.in_strong = true;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
let children = tag.children();
|
|
218
|
-
{
|
|
219
|
-
for child_handle in children.top().iter() {
|
|
220
|
-
super::walk_node(
|
|
221
|
-
child_handle,
|
|
222
|
-
parser,
|
|
223
|
-
&mut content,
|
|
224
|
-
options,
|
|
225
|
-
&legend_ctx,
|
|
226
|
-
depth + 1,
|
|
227
|
-
dom_ctx,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
let trimmed = content.trim();
|
|
233
|
-
if !trimmed.is_empty() {
|
|
234
|
-
if ctx.convert_as_inline {
|
|
235
|
-
output.push_str(trimmed);
|
|
236
|
-
} else {
|
|
237
|
-
let mut symbol = String::with_capacity(2);
|
|
238
|
-
symbol.push(options.strong_em_symbol);
|
|
239
|
-
symbol.push(options.strong_em_symbol);
|
|
240
|
-
output.push_str(&symbol);
|
|
241
|
-
output.push_str(trimmed);
|
|
242
|
-
output.push_str(&symbol);
|
|
243
|
-
output.push_str("\n\n");
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/// Handles the `<label>` element.
|
|
250
|
-
///
|
|
251
|
-
/// A label element associates text with a form control. It's rendered as
|
|
252
|
-
/// a block or inline element depending on context.
|
|
253
|
-
///
|
|
254
|
-
/// # Behavior
|
|
255
|
-
///
|
|
256
|
-
/// - Content is collected from children
|
|
257
|
-
/// - Non-empty content is output followed by blank lines (in block mode)
|
|
258
|
-
/// - Blank lines are suppressed in inline mode
|
|
259
|
-
pub fn handle_label(
|
|
260
|
-
_tag_name: &str,
|
|
261
|
-
node_handle: &tl::NodeHandle,
|
|
262
|
-
parser: &tl::Parser,
|
|
263
|
-
output: &mut String,
|
|
264
|
-
options: &crate::options::ConversionOptions,
|
|
265
|
-
ctx: &super::Context,
|
|
266
|
-
depth: usize,
|
|
267
|
-
dom_ctx: &super::DomContext,
|
|
268
|
-
) {
|
|
269
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
270
|
-
let mut content = String::new();
|
|
271
|
-
let children = tag.children();
|
|
272
|
-
{
|
|
273
|
-
for child_handle in children.top().iter() {
|
|
274
|
-
super::walk_node(child_handle, parser, &mut content, options, ctx, depth + 1, dom_ctx);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
let trimmed = content.trim();
|
|
279
|
-
if !trimmed.is_empty() {
|
|
280
|
-
output.push_str(trimmed);
|
|
281
|
-
if !ctx.convert_as_inline {
|
|
282
|
-
output.push_str("\n\n");
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/// Handles the `<input>` element.
|
|
289
|
-
///
|
|
290
|
-
/// An input element represents a form control for user input. Since input
|
|
291
|
-
/// elements typically have no text content, this handler produces no output.
|
|
292
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
293
|
-
#[allow(clippy::ptr_arg, clippy::needless_pass_by_ref_mut)]
|
|
294
|
-
pub fn handle_input(
|
|
295
|
-
_tag_name: &str,
|
|
296
|
-
node_handle: &tl::NodeHandle,
|
|
297
|
-
parser: &tl::Parser,
|
|
298
|
-
output: &mut String,
|
|
299
|
-
_options: &crate::options::ConversionOptions,
|
|
300
|
-
ctx: &super::Context,
|
|
301
|
-
depth: usize,
|
|
302
|
-
dom_ctx: &super::DomContext,
|
|
303
|
-
) {
|
|
304
|
-
#[cfg(feature = "visitor")]
|
|
305
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
306
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
307
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
308
|
-
|
|
309
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
310
|
-
let attributes = collect_tag_attributes(tag);
|
|
311
|
-
let node_id = node_handle.get_inner();
|
|
312
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
313
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
314
|
-
let input_type = tag
|
|
315
|
-
.attributes()
|
|
316
|
-
.get("type")
|
|
317
|
-
.flatten()
|
|
318
|
-
.map_or_else(|| std::borrow::Cow::Borrowed("text"), |v| v.as_utf8_str())
|
|
319
|
-
.into_owned();
|
|
320
|
-
let name = tag
|
|
321
|
-
.attributes()
|
|
322
|
-
.get("name")
|
|
323
|
-
.flatten()
|
|
324
|
-
.map(|v| v.as_utf8_str().into_owned());
|
|
325
|
-
let value = tag
|
|
326
|
-
.attributes()
|
|
327
|
-
.get("value")
|
|
328
|
-
.flatten()
|
|
329
|
-
.map(|v| v.as_utf8_str().into_owned());
|
|
330
|
-
let node_ctx = NodeContext {
|
|
331
|
-
node_type: NodeType::Input,
|
|
332
|
-
tag_name: "input".to_string(),
|
|
333
|
-
attributes,
|
|
334
|
-
depth,
|
|
335
|
-
index_in_parent,
|
|
336
|
-
parent_tag,
|
|
337
|
-
is_inline: true,
|
|
338
|
-
};
|
|
339
|
-
let visit_result = {
|
|
340
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
341
|
-
visitor.visit_input(&node_ctx, &input_type, name.as_deref(), value.as_deref())
|
|
342
|
-
};
|
|
343
|
-
match visit_result {
|
|
344
|
-
VisitResult::Continue => {}
|
|
345
|
-
VisitResult::Skip => (),
|
|
346
|
-
VisitResult::Custom(custom) => {
|
|
347
|
-
output.push_str(&custom);
|
|
348
|
-
}
|
|
349
|
-
VisitResult::PreserveHtml => {
|
|
350
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
351
|
-
output.push_str(&serialize_node(node_handle, parser));
|
|
352
|
-
}
|
|
353
|
-
VisitResult::Error(err) => {
|
|
354
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
355
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
// Input elements have no text content; render nothing
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/// Handles the `<textarea>` element.
|
|
365
|
-
///
|
|
366
|
-
/// A textarea element represents a multi-line text input. Its content is
|
|
367
|
-
/// rendered as plain text, with blank lines added after in block mode.
|
|
368
|
-
///
|
|
369
|
-
/// # Behavior
|
|
370
|
-
///
|
|
371
|
-
/// - Content is collected from children
|
|
372
|
-
/// - Blank lines are added after content in block mode only
|
|
373
|
-
pub fn handle_textarea(
|
|
374
|
-
_tag_name: &str,
|
|
375
|
-
node_handle: &tl::NodeHandle,
|
|
376
|
-
parser: &tl::Parser,
|
|
377
|
-
output: &mut String,
|
|
378
|
-
options: &crate::options::ConversionOptions,
|
|
379
|
-
ctx: &super::Context,
|
|
380
|
-
depth: usize,
|
|
381
|
-
dom_ctx: &super::DomContext,
|
|
382
|
-
) {
|
|
383
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
384
|
-
let start_len = output.len();
|
|
385
|
-
let children = tag.children();
|
|
386
|
-
{
|
|
387
|
-
for child_handle in children.top().iter() {
|
|
388
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if !ctx.convert_as_inline && output.len() > start_len {
|
|
393
|
-
output.push_str("\n\n");
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/// Handles the `<select>` element.
|
|
399
|
-
///
|
|
400
|
-
/// A select element represents a dropdown list of options. Its options are
|
|
401
|
-
/// rendered as a list, with newlines between options.
|
|
402
|
-
///
|
|
403
|
-
/// # Behavior
|
|
404
|
-
///
|
|
405
|
-
/// - Content (options) is collected from children
|
|
406
|
-
/// - A single newline is added after the select in block mode
|
|
407
|
-
pub fn handle_select(
|
|
408
|
-
_tag_name: &str,
|
|
409
|
-
node_handle: &tl::NodeHandle,
|
|
410
|
-
parser: &tl::Parser,
|
|
411
|
-
output: &mut String,
|
|
412
|
-
options: &crate::options::ConversionOptions,
|
|
413
|
-
ctx: &super::Context,
|
|
414
|
-
depth: usize,
|
|
415
|
-
dom_ctx: &super::DomContext,
|
|
416
|
-
) {
|
|
417
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
418
|
-
let start_len = output.len();
|
|
419
|
-
let children = tag.children();
|
|
420
|
-
{
|
|
421
|
-
for child_handle in children.top().iter() {
|
|
422
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if !ctx.convert_as_inline && output.len() > start_len {
|
|
427
|
-
output.push('\n');
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/// Handles the `<option>` element.
|
|
433
|
-
///
|
|
434
|
-
/// An option element represents a choice within a select element.
|
|
435
|
-
/// Selected options are marked with a bullet point (`*`) in block mode.
|
|
436
|
-
///
|
|
437
|
-
/// # Behavior
|
|
438
|
-
///
|
|
439
|
-
/// - Content is collected from children
|
|
440
|
-
/// - If the option has the `selected` attribute, it's prefixed with `* ` in block mode
|
|
441
|
-
/// - A newline is added after each option in block mode
|
|
442
|
-
pub fn handle_option(
|
|
443
|
-
_tag_name: &str,
|
|
444
|
-
node_handle: &tl::NodeHandle,
|
|
445
|
-
parser: &tl::Parser,
|
|
446
|
-
output: &mut String,
|
|
447
|
-
options: &crate::options::ConversionOptions,
|
|
448
|
-
ctx: &super::Context,
|
|
449
|
-
depth: usize,
|
|
450
|
-
dom_ctx: &super::DomContext,
|
|
451
|
-
) {
|
|
452
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
453
|
-
let selected = tag.attributes().iter().any(|(name, _)| name.as_ref() == "selected");
|
|
454
|
-
|
|
455
|
-
let mut text = String::new();
|
|
456
|
-
let children = tag.children();
|
|
457
|
-
{
|
|
458
|
-
for child_handle in children.top().iter() {
|
|
459
|
-
super::walk_node(child_handle, parser, &mut text, options, ctx, depth + 1, dom_ctx);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
let trimmed = text.trim();
|
|
464
|
-
if !trimmed.is_empty() {
|
|
465
|
-
if selected && !ctx.convert_as_inline {
|
|
466
|
-
output.push_str("* ");
|
|
467
|
-
}
|
|
468
|
-
output.push_str(trimmed);
|
|
469
|
-
if !ctx.convert_as_inline {
|
|
470
|
-
output.push('\n');
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/// Handles the `<optgroup>` element.
|
|
477
|
-
///
|
|
478
|
-
/// An optgroup element groups options within a select element with an optional label.
|
|
479
|
-
/// The label is rendered as strong (bold) text, followed by the grouped options.
|
|
480
|
-
///
|
|
481
|
-
/// # Behavior
|
|
482
|
-
///
|
|
483
|
-
/// - The `label` attribute is output as strong text (if present)
|
|
484
|
-
/// - Options within the group are rendered normally
|
|
485
|
-
pub fn handle_optgroup(
|
|
486
|
-
_tag_name: &str,
|
|
487
|
-
node_handle: &tl::NodeHandle,
|
|
488
|
-
parser: &tl::Parser,
|
|
489
|
-
output: &mut String,
|
|
490
|
-
options: &crate::options::ConversionOptions,
|
|
491
|
-
ctx: &super::Context,
|
|
492
|
-
depth: usize,
|
|
493
|
-
dom_ctx: &super::DomContext,
|
|
494
|
-
) {
|
|
495
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
496
|
-
let label = tag
|
|
497
|
-
.attributes()
|
|
498
|
-
.get("label")
|
|
499
|
-
.flatten()
|
|
500
|
-
.map_or(Cow::Borrowed(""), |v| v.as_utf8_str());
|
|
501
|
-
|
|
502
|
-
if !label.is_empty() {
|
|
503
|
-
let mut symbol = String::with_capacity(2);
|
|
504
|
-
symbol.push(options.strong_em_symbol);
|
|
505
|
-
symbol.push(options.strong_em_symbol);
|
|
506
|
-
output.push_str(&symbol);
|
|
507
|
-
output.push_str(&label);
|
|
508
|
-
output.push_str(&symbol);
|
|
509
|
-
output.push('\n');
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
let children = tag.children();
|
|
513
|
-
{
|
|
514
|
-
for child_handle in children.top().iter() {
|
|
515
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/// Handles the `<button>` element.
|
|
522
|
-
///
|
|
523
|
-
/// A button element represents a clickable button. Its text content is rendered
|
|
524
|
-
/// as plain text, with blank lines added in block mode.
|
|
525
|
-
///
|
|
526
|
-
/// # Behavior
|
|
527
|
-
///
|
|
528
|
-
/// - Content is collected from children
|
|
529
|
-
/// - Blank lines are added after content in block mode only
|
|
530
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
531
|
-
pub fn handle_button(
|
|
532
|
-
_tag_name: &str,
|
|
533
|
-
node_handle: &tl::NodeHandle,
|
|
534
|
-
parser: &tl::Parser,
|
|
535
|
-
output: &mut String,
|
|
536
|
-
options: &crate::options::ConversionOptions,
|
|
537
|
-
ctx: &super::Context,
|
|
538
|
-
depth: usize,
|
|
539
|
-
dom_ctx: &super::DomContext,
|
|
540
|
-
) {
|
|
541
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
542
|
-
#[cfg(feature = "visitor")]
|
|
543
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
544
|
-
use crate::converter::get_text_content;
|
|
545
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
546
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
547
|
-
|
|
548
|
-
let text = get_text_content(node_handle, parser, dom_ctx);
|
|
549
|
-
let attributes = collect_tag_attributes(tag);
|
|
550
|
-
let node_id = node_handle.get_inner();
|
|
551
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
552
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
553
|
-
let node_ctx = NodeContext {
|
|
554
|
-
node_type: NodeType::Button,
|
|
555
|
-
tag_name: "button".to_string(),
|
|
556
|
-
attributes,
|
|
557
|
-
depth,
|
|
558
|
-
index_in_parent,
|
|
559
|
-
parent_tag,
|
|
560
|
-
is_inline: true,
|
|
561
|
-
};
|
|
562
|
-
let visit_result = {
|
|
563
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
564
|
-
visitor.visit_button(&node_ctx, &text)
|
|
565
|
-
};
|
|
566
|
-
match visit_result {
|
|
567
|
-
VisitResult::Continue => {}
|
|
568
|
-
VisitResult::Skip => return,
|
|
569
|
-
VisitResult::Custom(custom) => {
|
|
570
|
-
output.push_str(&custom);
|
|
571
|
-
if !ctx.convert_as_inline && !custom.ends_with('\n') {
|
|
572
|
-
output.push_str("\n\n");
|
|
573
|
-
}
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
VisitResult::PreserveHtml => {
|
|
577
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
578
|
-
output.push_str(&serialize_node(node_handle, parser));
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
VisitResult::Error(err) => {
|
|
582
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
583
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
584
|
-
}
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
let start_len = output.len();
|
|
591
|
-
let children = tag.children();
|
|
592
|
-
{
|
|
593
|
-
for child_handle in children.top().iter() {
|
|
594
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
if !ctx.convert_as_inline && output.len() > start_len {
|
|
599
|
-
output.push_str("\n\n");
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/// Handles the `<progress>` element.
|
|
605
|
-
///
|
|
606
|
-
/// A progress element represents a progress bar. It typically has no visible
|
|
607
|
-
/// text content, but we render any child content present.
|
|
608
|
-
///
|
|
609
|
-
/// # Behavior
|
|
610
|
-
///
|
|
611
|
-
/// - Content is collected from children (usually empty)
|
|
612
|
-
/// - Blank lines are added after content in block mode only
|
|
613
|
-
pub fn handle_progress(
|
|
614
|
-
_tag_name: &str,
|
|
615
|
-
node_handle: &tl::NodeHandle,
|
|
616
|
-
parser: &tl::Parser,
|
|
617
|
-
output: &mut String,
|
|
618
|
-
options: &crate::options::ConversionOptions,
|
|
619
|
-
ctx: &super::Context,
|
|
620
|
-
depth: usize,
|
|
621
|
-
dom_ctx: &super::DomContext,
|
|
622
|
-
) {
|
|
623
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
624
|
-
let start_len = output.len();
|
|
625
|
-
let children = tag.children();
|
|
626
|
-
{
|
|
627
|
-
for child_handle in children.top().iter() {
|
|
628
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
if !ctx.convert_as_inline && output.len() > start_len {
|
|
633
|
-
output.push_str("\n\n");
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
/// Handles the `<meter>` element.
|
|
639
|
-
///
|
|
640
|
-
/// A meter element represents a scalar measurement (e.g., disk usage, temperature).
|
|
641
|
-
/// It typically has no visible text content, but we render any child content.
|
|
642
|
-
///
|
|
643
|
-
/// # Behavior
|
|
644
|
-
///
|
|
645
|
-
/// - Content is collected from children (usually empty)
|
|
646
|
-
/// - Blank lines are added after content in block mode only
|
|
647
|
-
pub fn handle_meter(
|
|
648
|
-
_tag_name: &str,
|
|
649
|
-
node_handle: &tl::NodeHandle,
|
|
650
|
-
parser: &tl::Parser,
|
|
651
|
-
output: &mut String,
|
|
652
|
-
options: &crate::options::ConversionOptions,
|
|
653
|
-
ctx: &super::Context,
|
|
654
|
-
depth: usize,
|
|
655
|
-
dom_ctx: &super::DomContext,
|
|
656
|
-
) {
|
|
657
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
658
|
-
let start_len = output.len();
|
|
659
|
-
let children = tag.children();
|
|
660
|
-
{
|
|
661
|
-
for child_handle in children.top().iter() {
|
|
662
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
if !ctx.convert_as_inline && output.len() > start_len {
|
|
667
|
-
output.push_str("\n\n");
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/// Handles the `<output>` element.
|
|
673
|
-
///
|
|
674
|
-
/// An output element represents the result of a calculation. It renders its
|
|
675
|
-
/// text content as plain output, with blank lines in block mode.
|
|
676
|
-
///
|
|
677
|
-
/// # Behavior
|
|
678
|
-
///
|
|
679
|
-
/// - Content is collected from children
|
|
680
|
-
/// - Blank lines are added after content in block mode only
|
|
681
|
-
pub fn handle_output(
|
|
682
|
-
_tag_name: &str,
|
|
683
|
-
node_handle: &tl::NodeHandle,
|
|
684
|
-
parser: &tl::Parser,
|
|
685
|
-
output: &mut String,
|
|
686
|
-
options: &crate::options::ConversionOptions,
|
|
687
|
-
ctx: &super::Context,
|
|
688
|
-
depth: usize,
|
|
689
|
-
dom_ctx: &super::DomContext,
|
|
690
|
-
) {
|
|
691
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
692
|
-
let start_len = output.len();
|
|
693
|
-
let children = tag.children();
|
|
694
|
-
{
|
|
695
|
-
for child_handle in children.top().iter() {
|
|
696
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
if !ctx.convert_as_inline && output.len() > start_len {
|
|
701
|
-
output.push_str("\n\n");
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/// Handles the `<datalist>` element.
|
|
707
|
-
///
|
|
708
|
-
/// A datalist element provides a list of predefined options for an input element.
|
|
709
|
-
/// Options are rendered as a list with newlines between them.
|
|
710
|
-
///
|
|
711
|
-
/// # Behavior
|
|
712
|
-
///
|
|
713
|
-
/// - Content (options) is collected from children
|
|
714
|
-
/// - A single newline is added after the datalist in block mode
|
|
715
|
-
pub fn handle_datalist(
|
|
716
|
-
_tag_name: &str,
|
|
717
|
-
node_handle: &tl::NodeHandle,
|
|
718
|
-
parser: &tl::Parser,
|
|
719
|
-
output: &mut String,
|
|
720
|
-
options: &crate::options::ConversionOptions,
|
|
721
|
-
ctx: &super::Context,
|
|
722
|
-
depth: usize,
|
|
723
|
-
dom_ctx: &super::DomContext,
|
|
724
|
-
) {
|
|
725
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
726
|
-
let start_len = output.len();
|
|
727
|
-
let children = tag.children();
|
|
728
|
-
{
|
|
729
|
-
for child_handle in children.top().iter() {
|
|
730
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
if !ctx.convert_as_inline && output.len() > start_len {
|
|
735
|
-
output.push('\n');
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
/// Dispatcher for form elements.
|
|
741
|
-
///
|
|
742
|
-
/// Routes all form-related elements to their respective handlers.
|
|
743
|
-
pub fn handle(
|
|
744
|
-
tag_name: &str,
|
|
745
|
-
node_handle: &tl::NodeHandle,
|
|
746
|
-
parser: &tl::Parser,
|
|
747
|
-
output: &mut String,
|
|
748
|
-
options: &crate::options::ConversionOptions,
|
|
749
|
-
ctx: &super::Context,
|
|
750
|
-
depth: usize,
|
|
751
|
-
dom_ctx: &super::DomContext,
|
|
752
|
-
) {
|
|
753
|
-
match tag_name {
|
|
754
|
-
"form" => handle_form(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
755
|
-
"fieldset" => handle_fieldset(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
756
|
-
"legend" => handle_legend(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
757
|
-
"label" => handle_label(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
758
|
-
"input" => handle_input(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
759
|
-
"textarea" => handle_textarea(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
760
|
-
"select" => handle_select(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
761
|
-
"option" => handle_option(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
762
|
-
"optgroup" => handle_optgroup(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
763
|
-
"button" => handle_button(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
764
|
-
"progress" => handle_progress(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
765
|
-
"meter" => handle_meter(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
766
|
-
"output" => handle_output(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
767
|
-
"datalist" => handle_datalist(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
768
|
-
_ => {}
|
|
769
|
-
}
|
|
770
|
-
}
|