Skip to main content

ftml/render/
handle.rs

1/*
2 * render/handle.rs
3 *
4 * ftml - Library to parse Wikidot text
5 * Copyright (C) 2019-2026 Wikijump Team
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21use crate::data::{KarmaLevel, PageInfo, UserInfo};
22use crate::settings::WikitextSettings;
23use crate::tree::{FileSource, LinkLabel, LinkLocation, Module};
24use crate::url::BuildSiteUrl;
25use std::borrow::Cow;
26use std::num::NonZeroUsize;
27
28#[derive(Debug)]
29pub struct Handle;
30
31impl Handle {
32    pub fn render_module(&self, buffer: &mut String, module: &Module) {
33        // Modules only render to HTML
34        debug!("Rendering module '{}'", module.name());
35        str_write!(buffer, "<p>TODO: module {}</p>", module.name());
36    }
37
38    pub fn get_page_title(&self, _site: &str, _page: &str) -> Option<String> {
39        debug!("Fetching page title");
40
41        // TODO
42        Some(format!("TODO: actual title ({_site} {_page})"))
43    }
44
45    pub fn get_page_exists(&self, _site: &str, _page: &str) -> bool {
46        debug!("Checking page existence");
47
48        // For testing
49        #[cfg(test)]
50        if _page == "missing" {
51            return false;
52        }
53
54        // TODO
55        true
56    }
57
58    pub fn get_user_info<'a>(&self, name: &'a str) -> Option<UserInfo<'a>> {
59        debug!("Fetching user info (name '{name}')");
60        let mut info = UserInfo::dummy();
61        info.user_name = cow!(name);
62        info.user_profile_url = Cow::Owned(format!("/user:info/{name}"));
63        Some(info)
64    }
65
66    pub fn get_file_link<'a>(
67        &self,
68        source: &FileSource<'a>,
69        info: &PageInfo,
70        settings: &WikitextSettings,
71    ) -> Option<Cow<'a, str>> {
72        let (site, page, file): (&str, &str, &str) = match source {
73            FileSource::Url(url) => return Some(Cow::clone(url)),
74            FileSource::File1 { .. }
75            | FileSource::File2 { .. }
76            | FileSource::File3 { .. }
77                if !settings.allow_local_paths =>
78            {
79                warn!("Specified path file source when local paths are disabled");
80                return None;
81            }
82            FileSource::File1 { file } => (&info.site, &info.page, file),
83            FileSource::File2 { page, file } => (&info.site, page, file),
84            FileSource::File3 { site, page, file } => (site, page, file),
85        };
86
87        // TODO: emit url
88        Some(Cow::Owned(format!(
89            "https://{site}.wjfiles.com/local--files/{page}/{file}",
90        )))
91    }
92
93    pub fn get_link_label<F>(
94        &self,
95        site: &str,
96        link: &LinkLocation,
97        label: &LinkLabel,
98        f: F,
99    ) where
100        F: FnOnce(&str),
101    {
102        let page_title;
103        let label_text = match label {
104            LinkLabel::Text(text) | LinkLabel::Slug(text) => text,
105            LinkLabel::Url => match link {
106                LinkLocation::Url(url) => url.as_ref(),
107                LinkLocation::Page(_) => {
108                    panic!("Requested a URL link label for a page");
109                }
110            },
111            LinkLabel::Page => match link {
112                LinkLocation::Page(page_ref) => {
113                    let (site, page, _) = page_ref.fields_or(site);
114                    page_title = match self.get_page_title(site, page) {
115                        Some(title) => title,
116                        None => page_ref.to_string(),
117                    };
118
119                    &page_title
120                }
121                LinkLocation::Url(_) => {
122                    panic!("Requested a page title link label for a URL");
123                }
124            },
125        };
126
127        f(label_text);
128    }
129
130    pub fn get_karma_style(&self, karma: KarmaLevel) -> &'static str {
131        // TODO replace these with inline data image URIs
132        match karma {
133            KarmaLevel::Zero => {
134                "background-image: url(https://www.wikidot.com/userkarma.php?u=8976177)"
135            }
136            KarmaLevel::One => {
137                "background-image: url(https://www.wikidot.com/userkarma.php?u=172570)"
138            }
139            KarmaLevel::Two => {
140                "background-image: url(https://www.wikidot.com/userkarma.php?u=172952)"
141            }
142            KarmaLevel::Three => {
143                "background-image: url(https://www.wikidot.com/userkarma.php?u=172904)"
144            }
145            KarmaLevel::Four => {
146                "background-image: url(https://www.wikidot.com/userkarma.php?u=6040770)"
147            }
148            KarmaLevel::Five => {
149                "background-image: url(https://www.wikidot.com/userkarma.php?u=4598089)"
150            }
151        }
152    }
153
154    pub fn get_message(&self, language: &str, message: &str) -> &'static str {
155        debug!("Fetching message (language {language}, key {message})");
156
157        let _ = language;
158
159        // TODO
160        match message {
161            "button-copy-clipboard" => "Copy to Clipboard",
162            "collapsible-open" => "+ open block",
163            "collapsible-hide" => "- hide block",
164            "table-of-contents" => "Table of Contents",
165            "footnote" => "Footnote",
166            "footnote-block-title" => "Footnotes",
167            "bibliography-reference" => "Reference",
168            "bibliography-block-title" => "Bibliography",
169            "bibliography-cite-not-found" => "Bibliography item not found",
170            "image-context-bad" => "No images in this context",
171            "user-missing-pre" => "",
172            "user-missing-post" => " does not match any existing user name",
173            _ => {
174                error!("Unknown message requested (key {message})");
175                "?"
176            }
177        }
178    }
179
180    pub fn post_html(&self, info: &PageInfo, html: &str) -> String {
181        debug!("Submitting HTML to create iframe-able snippet");
182
183        let _ = info;
184        let _ = html;
185
186        // TODO
187        str!("https://example.com/")
188    }
189
190    pub fn post_code(&self, index: NonZeroUsize, code: &str) {
191        debug!("Submitting code snippet (index {})", index.get());
192
193        let _ = index;
194        let _ = code;
195
196        // TODO
197    }
198}
199
200impl BuildSiteUrl for Handle {
201    fn build_url(&self, site: &str, path: &str, extra: Option<&str>) -> String {
202        // TODO make this a parser setting
203        // get url of wikijump instance here
204
205        // TODO
206        let extra = extra.unwrap_or("");
207        format!("https://{site}.wikijump.com/{path}{extra}")
208    }
209}