mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-01-15 01:00:02 +00:00
implement view-source feature
This commit is contained in:
parent
9784a8a1a1
commit
614aa1d71a
@ -95,8 +95,9 @@ GTK 4 / Libadwaita client written in Rust
|
||||
* [ ] [NPS](https://nightfall.city/nps/info/specification.txt)
|
||||
* [ ] Localhost
|
||||
* [ ] `file://` - localhost browser
|
||||
* [ ] `config://` - low-level key/value settings editor
|
||||
* [ ] `view-source://` - page source viewer (where supported)
|
||||
* [ ] System
|
||||
* [ ] `config:` - low-level key/value settings editor
|
||||
* [x] `view-source:` - page source viewer (where supported)
|
||||
|
||||
### Media types
|
||||
|
||||
|
@ -197,6 +197,12 @@ impl Page {
|
||||
self.navigation.request.widget.entry.text()
|
||||
};
|
||||
|
||||
// Detect source view mode, return `request` string prepared for route
|
||||
let (request, is_view_source) = match request.strip_prefix("view-source:") {
|
||||
Some(postfix) => (gformat!("{}", postfix.to_string()), true),
|
||||
None => (request, false),
|
||||
};
|
||||
|
||||
// Update
|
||||
self.meta.set_status(Status::Reload).set_title("Loading..");
|
||||
self.browser_action.update.activate(Some(&id));
|
||||
@ -207,7 +213,7 @@ impl Page {
|
||||
// Route by scheme
|
||||
match uri.scheme().as_str() {
|
||||
"file" => todo!(),
|
||||
"gemini" => self.load_gemini(uri, is_history), // @TODO
|
||||
"gemini" => self.load_gemini(uri, is_history, is_view_source), // @TODO
|
||||
scheme => {
|
||||
// Define common data
|
||||
let status = Status::Failure;
|
||||
@ -379,7 +385,7 @@ impl Page {
|
||||
// Private helpers
|
||||
|
||||
// @TODO move outside
|
||||
fn load_gemini(&self, uri: Uri, is_history: bool) {
|
||||
fn load_gemini(&self, uri: Uri, is_history: bool, is_view_source: bool) {
|
||||
// Init shared clones
|
||||
let cancellable = self.client.cancellable();
|
||||
let update = self.browser_action.update.clone();
|
||||
@ -489,20 +495,26 @@ impl Page {
|
||||
move |result|{
|
||||
match result {
|
||||
Ok(buffer) => {
|
||||
// Set children component
|
||||
let text_gemini = content.to_text_gemini(
|
||||
&uri,
|
||||
&buffer.data
|
||||
);
|
||||
|
||||
let title = match text_gemini.meta.title {
|
||||
Some(ref title) => title,
|
||||
None => &uri_to_title(&uri)
|
||||
// Set children component,
|
||||
// extract title from meta parsed
|
||||
let title = if is_view_source {
|
||||
content.to_text_source(
|
||||
&buffer.data
|
||||
);
|
||||
uri_to_title(&uri)
|
||||
} else {
|
||||
match content.to_text_gemini(
|
||||
&uri,
|
||||
&buffer.data
|
||||
).meta.title {
|
||||
Some(meta_title) => meta_title,
|
||||
None => uri_to_title(&uri)
|
||||
}
|
||||
};
|
||||
|
||||
// Update page meta
|
||||
meta.set_status(Status::Success)
|
||||
.set_title(title);
|
||||
.set_title(&title);
|
||||
|
||||
// Update window components
|
||||
update.activate(Some(&id));
|
||||
|
@ -92,7 +92,7 @@ impl Content {
|
||||
/// * could be useful to extract document title parsed from Gemtext
|
||||
pub fn to_text_gemini(&self, base: &Uri, data: &str) -> Text {
|
||||
self.clean();
|
||||
let text = Text::gemini(
|
||||
let text = Text::new_gemini(
|
||||
data,
|
||||
base,
|
||||
(self.window_action.clone(), self.tab_action.clone()),
|
||||
@ -101,6 +101,13 @@ impl Content {
|
||||
text
|
||||
}
|
||||
|
||||
pub fn to_text_source(&self, data: &str) -> Text {
|
||||
self.clean();
|
||||
let text = Text::new_source(data);
|
||||
self.gobject.append(&text.scrolled_window);
|
||||
text
|
||||
}
|
||||
|
||||
/// Remove all children components from `Self`
|
||||
pub fn clean(&self) {
|
||||
while let Some(child) = self.gobject.last_child() {
|
||||
|
@ -1,6 +1,8 @@
|
||||
mod gemini;
|
||||
mod source;
|
||||
|
||||
use gemini::Gemini;
|
||||
use source::Source;
|
||||
|
||||
use crate::app::browser::window::{tab::item::Action as TabAction, Action as WindowAction};
|
||||
use gtk::{glib::Uri, ScrolledWindow};
|
||||
@ -16,24 +18,38 @@ pub struct Text {
|
||||
}
|
||||
|
||||
impl Text {
|
||||
// Construct
|
||||
pub fn gemini(gemtext: &str, base: &Uri, actions: (Rc<WindowAction>, Rc<TabAction>)) -> Self {
|
||||
// Init components
|
||||
// Constructors
|
||||
|
||||
pub fn new_gemini(
|
||||
gemtext: &str,
|
||||
base: &Uri,
|
||||
actions: (Rc<WindowAction>, Rc<TabAction>),
|
||||
) -> Self {
|
||||
// Init widget driver
|
||||
let gemini = Gemini::new(gemtext, base, actions);
|
||||
|
||||
// Init meta
|
||||
let meta = Meta {
|
||||
title: gemini.reader.title.clone(),
|
||||
};
|
||||
|
||||
// Init scrolled_window
|
||||
// Init scrolled container
|
||||
let scrolled_window = ScrolledWindow::builder().build();
|
||||
|
||||
scrolled_window.set_child(Some(&gemini.widget.clamp_scrollable));
|
||||
|
||||
// Result
|
||||
Self {
|
||||
meta,
|
||||
meta: Meta {
|
||||
title: gemini.reader.title.clone(),
|
||||
},
|
||||
scrolled_window,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_source(data: &str) -> Self {
|
||||
// Init scrolled container
|
||||
let scrolled_window = ScrolledWindow::builder().build();
|
||||
scrolled_window.set_child(Some(&Source::new(data).text_view));
|
||||
|
||||
// Result
|
||||
Self {
|
||||
meta: Meta { title: None },
|
||||
scrolled_window,
|
||||
}
|
||||
}
|
||||
|
25
src/app/browser/window/tab/item/page/content/text/source.rs
Normal file
25
src/app/browser/window/tab/item/page/content/text/source.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use gtk::{TextBuffer, TextView};
|
||||
|
||||
const MARGIN: i32 = 8;
|
||||
|
||||
pub struct Source {
|
||||
pub text_view: TextView,
|
||||
}
|
||||
|
||||
impl Source {
|
||||
pub fn new(data: &str) -> Self {
|
||||
Self {
|
||||
text_view: TextView::builder()
|
||||
.bottom_margin(MARGIN)
|
||||
.buffer(&TextBuffer::builder().text(data).build())
|
||||
.cursor_visible(false)
|
||||
.editable(false)
|
||||
.left_margin(MARGIN)
|
||||
.monospace(true)
|
||||
.right_margin(MARGIN)
|
||||
.top_margin(MARGIN)
|
||||
.vexpand(true)
|
||||
.build(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user