mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-02-03 23:14:13 +00:00
page controller contains lot of code, begin components reorganization before implement new features
This commit is contained in:
parent
2cab9e4287
commit
a35d86a630
@ -5,7 +5,6 @@ mod error;
|
|||||||
mod input;
|
mod input;
|
||||||
mod mode;
|
mod mode;
|
||||||
mod navigation;
|
mod navigation;
|
||||||
mod redirect;
|
|
||||||
mod search;
|
mod search;
|
||||||
mod status;
|
mod status;
|
||||||
mod widget;
|
mod widget;
|
||||||
@ -16,7 +15,6 @@ use error::Error;
|
|||||||
use input::Input;
|
use input::Input;
|
||||||
use mode::Mode;
|
use mode::Mode;
|
||||||
use navigation::Navigation;
|
use navigation::Navigation;
|
||||||
use redirect::Redirect;
|
|
||||||
use search::Search;
|
use search::Search;
|
||||||
use status::Status;
|
use status::Status;
|
||||||
use widget::Widget;
|
use widget::Widget;
|
||||||
@ -38,7 +36,6 @@ pub struct Page {
|
|||||||
profile: Rc<Profile>,
|
profile: Rc<Profile>,
|
||||||
status: Rc<RefCell<Status>>,
|
status: Rc<RefCell<Status>>,
|
||||||
title: Rc<RefCell<GString>>,
|
title: Rc<RefCell<GString>>,
|
||||||
redirect: Rc<Redirect>,
|
|
||||||
// Actions
|
// Actions
|
||||||
browser_action: Rc<BrowserAction>,
|
browser_action: Rc<BrowserAction>,
|
||||||
tab_action: Rc<TabAction>,
|
tab_action: Rc<TabAction>,
|
||||||
@ -90,7 +87,6 @@ impl Page {
|
|||||||
Self {
|
Self {
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
profile: profile.clone(),
|
profile: profile.clone(),
|
||||||
redirect: Rc::new(Redirect::new()),
|
|
||||||
status: Rc::new(RefCell::new(Status::New)),
|
status: Rc::new(RefCell::new(Status::New)),
|
||||||
title: Rc::new(RefCell::new(gformat!("New page"))),
|
title: Rc::new(RefCell::new(gformat!("New page"))),
|
||||||
// Actions
|
// Actions
|
||||||
@ -170,10 +166,6 @@ impl Page {
|
|||||||
/// Main loader for different protocols, that routed by scheme
|
/// Main loader for different protocols, that routed by scheme
|
||||||
/// * every protocol has it own (children) method implementation
|
/// * every protocol has it own (children) method implementation
|
||||||
pub fn load(&self, is_history: bool) {
|
pub fn load(&self, is_history: bool) {
|
||||||
/// Global limit to prevent infinitive redirects (ALL protocols)
|
|
||||||
/// * every protocol implementation has own value checker, according to specification
|
|
||||||
const DEFAULT_MAX_REDIRECT_COUNT: usize = 10;
|
|
||||||
|
|
||||||
// Move focus out from navigation entry
|
// Move focus out from navigation entry
|
||||||
self.browser_action
|
self.browser_action
|
||||||
.escape
|
.escape
|
||||||
@ -186,27 +178,22 @@ impl Page {
|
|||||||
self.search.unset();
|
self.search.unset();
|
||||||
self.input.unset();
|
self.input.unset();
|
||||||
|
|
||||||
// Prevent infinitive redirection
|
|
||||||
if self.redirect.count() > DEFAULT_MAX_REDIRECT_COUNT {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try redirect request
|
// Try redirect request
|
||||||
let request = if let Some(redirect) = self.redirect.last() {
|
let request = if let Some(redirect) = self.client.redirect.last() {
|
||||||
// Gemini protocol may provide background (temporarily) redirects
|
// Gemini protocol may provide background (temporarily) redirects
|
||||||
if redirect.is_foreground {
|
if redirect.is_foreground {
|
||||||
self.navigation
|
self.navigation
|
||||||
.request
|
.request
|
||||||
.widget
|
.widget
|
||||||
.entry
|
.entry
|
||||||
.set_text(&redirect.request);
|
.set_text(&redirect.request.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return value from redirection holder
|
// Return value from redirection holder
|
||||||
Mode::from(&redirect.request, redirect.referrer.as_ref())
|
Mode::from(&redirect.request.to_str(), None /*redirect.referrer*/) // @TODO
|
||||||
} else {
|
} else {
|
||||||
// Reset redirect counter as request value taken from user input
|
// Reset redirect counter as request value taken from user input
|
||||||
self.redirect.clear();
|
self.client.redirect.clear();
|
||||||
|
|
||||||
// Return value from navigation entry
|
// Return value from navigation entry
|
||||||
Mode::from(&self.navigation.request.widget.entry.text(), None)
|
Mode::from(&self.navigation.request.widget.entry.text(), None)
|
||||||
@ -424,7 +411,7 @@ impl Page {
|
|||||||
let search = self.search.clone();
|
let search = self.search.clone();
|
||||||
let tab_action = self.tab_action.clone();
|
let tab_action = self.tab_action.clone();
|
||||||
let window_action = self.window_action.clone();
|
let window_action = self.window_action.clone();
|
||||||
let redirect = self.redirect.clone();
|
let redirect = self.client.redirect.clone();
|
||||||
|
|
||||||
// Listen for connection status updates
|
// Listen for connection status updates
|
||||||
self.client.gemini.socket.connect_event({
|
self.client.gemini.socket.connect_event({
|
||||||
@ -775,11 +762,11 @@ impl Page {
|
|||||||
redirect.add(
|
redirect.add(
|
||||||
// skip query and fragment by protocol requirements
|
// skip query and fragment by protocol requirements
|
||||||
// @TODO review fragment specification
|
// @TODO review fragment specification
|
||||||
resolved_uri.to_string_partial(
|
Uri::parse(&resolved_uri.to_string_partial(
|
||||||
UriHideFlags::FRAGMENT | UriHideFlags::QUERY
|
UriHideFlags::FRAGMENT | UriHideFlags::QUERY
|
||||||
),
|
), UriFlags::NONE).unwrap(), // @TODO handle
|
||||||
// referrer
|
// referrer
|
||||||
Some(navigation.request.widget.entry.text()),
|
Some(uri.clone()),
|
||||||
// set follow policy based on status code
|
// set follow policy based on status code
|
||||||
matches!(response.meta.status, response::meta::Status::PermanentRedirect),
|
matches!(response.meta.status, response::meta::Status::PermanentRedirect),
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
|
mod redirect;
|
||||||
|
mod status;
|
||||||
|
|
||||||
|
use redirect::Redirect;
|
||||||
|
use status::Status;
|
||||||
|
|
||||||
use gtk::{gio::Cancellable, prelude::CancellableExt};
|
use gtk::{gio::Cancellable, prelude::CancellableExt};
|
||||||
use std::cell::Cell;
|
use std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
/// Multi-client holder for single `Page` object
|
/// Multi-client holder for single `Page` object
|
||||||
///
|
///
|
||||||
@ -10,7 +19,11 @@ use std::cell::Cell;
|
|||||||
pub struct Client {
|
pub struct Client {
|
||||||
// Shared reference to cancel async operations
|
// Shared reference to cancel async operations
|
||||||
cancellable: Cell<Cancellable>,
|
cancellable: Cell<Cancellable>,
|
||||||
// Clients
|
// Redirects resolver for different protocols
|
||||||
|
pub redirect: Rc<Redirect>,
|
||||||
|
// Track update status
|
||||||
|
status: Rc<RefCell<Status>>,
|
||||||
|
// Drivers
|
||||||
pub gemini: gemini::Client,
|
pub gemini: gemini::Client,
|
||||||
// other clients..
|
// other clients..
|
||||||
}
|
}
|
||||||
@ -28,6 +41,8 @@ impl Client {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cancellable: Cell::new(Cancellable::new()),
|
cancellable: Cell::new(Cancellable::new()),
|
||||||
|
redirect: Rc::new(Redirect::new()),
|
||||||
|
status: Rc::new(RefCell::new(Status::Cancellable)),
|
||||||
gemini: gemini::Client::new(),
|
gemini: gemini::Client::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,9 +56,23 @@ impl Client {
|
|||||||
let previous = self.cancellable.replace(cancellable.clone());
|
let previous = self.cancellable.replace(cancellable.clone());
|
||||||
if !previous.is_cancelled() {
|
if !previous.is_cancelled() {
|
||||||
previous.cancel();
|
previous.cancel();
|
||||||
|
self.status.replace(Status::Cancelled);
|
||||||
|
} else {
|
||||||
|
self.status.replace(Status::Cancellable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
cancellable
|
cancellable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn request(&self, query: &str) {
|
||||||
|
self.status.replace(Status::Request(query.to_string()));
|
||||||
|
|
||||||
|
// Forcefully prevent infinitive redirection
|
||||||
|
// * this condition just to make sure that client will never stuck by driver implementation issue
|
||||||
|
if self.redirect.count() > redirect::LIMIT {
|
||||||
|
self.status.replace(Status::RedirectLimit(redirect::LIMIT));
|
||||||
|
// @TODO return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
67
src/app/browser/window/tab/item/page/client/redirect.rs
Normal file
67
src/app/browser/window/tab/item/page/client/redirect.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
mod item;
|
||||||
|
use item::Item;
|
||||||
|
|
||||||
|
use gtk::glib::Uri;
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
|
||||||
|
/// Global limit to prevent infinitive redirection issues
|
||||||
|
/// * defined value is globally applicable to ALL drivers
|
||||||
|
/// * every driver implement its own value, according to protocol specification
|
||||||
|
/// * the `Client` will forcefully break redirection loop when iteration reach this value
|
||||||
|
pub const LIMIT: usize = 10; // @TODO make optional
|
||||||
|
|
||||||
|
pub struct Redirect {
|
||||||
|
chain: RefCell<Vec<Item>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Redirect {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Redirect {
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
/// Create new `Self`
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
chain: RefCell::new(Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
|
||||||
|
/// Register new redirect in chain
|
||||||
|
pub fn add(&self, request: Uri, referrer: Option<Uri>, is_foreground: bool) -> &Self {
|
||||||
|
self.chain.borrow_mut().push(Item {
|
||||||
|
request,
|
||||||
|
referrer,
|
||||||
|
is_foreground,
|
||||||
|
is_processed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear redirect chain
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.chain.borrow_mut().clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
|
||||||
|
/// Get total redirects count in chain
|
||||||
|
pub fn count(&self) -> usize {
|
||||||
|
self.chain.borrow().len() + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get last redirection `Item` copy
|
||||||
|
pub fn last(&self) -> Option<Item> {
|
||||||
|
if let Some(redirect) = self.chain.borrow().last() {
|
||||||
|
if !redirect.is_processed.replace(true) {
|
||||||
|
return Some(redirect.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
11
src/app/browser/window/tab/item/page/client/redirect/item.rs
Normal file
11
src/app/browser/window/tab/item/page/client/redirect/item.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use gtk::glib::Uri;
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
/// Single redirect `Item`
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Item {
|
||||||
|
pub is_foreground: bool,
|
||||||
|
pub is_processed: Cell<bool>,
|
||||||
|
pub referrer: Option<Uri>,
|
||||||
|
pub request: Uri,
|
||||||
|
}
|
36
src/app/browser/window/tab/item/page/client/status.rs
Normal file
36
src/app/browser/window/tab/item/page/client/status.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use std::fmt::{Display, Formatter, Result};
|
||||||
|
|
||||||
|
/// Local `Client` status
|
||||||
|
/// * not same as the Gemini status!
|
||||||
|
pub enum Status {
|
||||||
|
/// Ready to use (or cancel from outside)
|
||||||
|
Cancellable,
|
||||||
|
/// Operation cancelled, new `Cancellable` required to continue
|
||||||
|
Cancelled,
|
||||||
|
/// Redirection count limit reached by protocol driver or global settings
|
||||||
|
RedirectLimit(usize),
|
||||||
|
/// New `request` begin
|
||||||
|
Request(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Status {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||||
|
match self {
|
||||||
|
Self::Cancellable => {
|
||||||
|
write!(f, "Ready to use (or cancel from outside)")
|
||||||
|
}
|
||||||
|
Self::Cancelled => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Operation cancelled, new `Cancellable` required to continue"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::RedirectLimit(count) => {
|
||||||
|
write!(f, "Redirection count limit ({count}) reached by protocol driver or global settings")
|
||||||
|
}
|
||||||
|
Self::Request(value) => {
|
||||||
|
write!(f, "Request `{value}`...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,57 +0,0 @@
|
|||||||
mod item;
|
|
||||||
use item::Item;
|
|
||||||
|
|
||||||
use gtk::glib::GString;
|
|
||||||
use std::cell::{Cell, RefCell};
|
|
||||||
|
|
||||||
pub struct Redirect {
|
|
||||||
index: RefCell<Vec<Item>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Redirect {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Redirect {
|
|
||||||
// Constructors
|
|
||||||
|
|
||||||
/// Create new `Self`
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
index: RefCell::new(Vec::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
|
|
||||||
pub fn add(&self, request: GString, referrer: Option<GString>, is_foreground: bool) -> &Self {
|
|
||||||
self.index.borrow_mut().push(Item {
|
|
||||||
request,
|
|
||||||
referrer,
|
|
||||||
is_foreground,
|
|
||||||
is_processed: Cell::new(false),
|
|
||||||
});
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&self) {
|
|
||||||
self.index.borrow_mut().clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
|
|
||||||
pub fn count(&self) -> usize {
|
|
||||||
self.index.borrow().len() + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn last(&self) -> Option<Item> {
|
|
||||||
if let Some(redirect) = self.index.borrow().last() {
|
|
||||||
if !redirect.is_processed.replace(true) {
|
|
||||||
return Some(redirect.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user