diff --git a/napture/src/b9/html.rs b/napture/src/b9/html.rs
index e40b2300..a085c0c4 100644
--- a/napture/src/b9/html.rs
+++ b/napture/src/b9/html.rs
@@ -1,6 +1,6 @@
extern crate html_parser;
-use crate::{lualog, Tab, globals::LUA_TIMEOUTS};
+use crate::{globals::LUA_TIMEOUTS, lualog, Tab};
use super::{
css::{self, Styleable},
@@ -26,7 +26,7 @@ fn decode_html_entities>(s: T) -> String {
decode_html_entities(s.as_ref()).to_string()
}
-async fn parse_html(mut url: String) -> Result<(Node, Node)> {
+async fn parse_html(mut url: String) -> Result<(Node, Node, String)> {
let mut is_html = true;
let mut file_name = String::new();
@@ -79,7 +79,7 @@ async fn parse_html(mut url: String) -> Result<(Node, Node)> {
}
};
- Ok((head, body))
+ Ok((head, body, html))
}
fn find_element_by_name(elements: &Vec, name: &str) -> Option {
@@ -128,7 +128,7 @@ pub async fn build_ui(
let mut css: String = css::reset_css();
- let (head, body) = match parse_html(furl.to_string()).await {
+ let (head, body, source_html) = match parse_html(furl.to_string()).await {
Ok(ok) => ok,
Err(e) => {
eprintln!("Couldn't parse HTML: {}", e);
@@ -136,6 +136,12 @@ pub async fn build_ui(
}
};
+ // add html to source here after parse_html()
+ {
+ let mut page_source = tab.page_source.borrow_mut();
+ page_source.add_file("index.html".to_string(), source_html.to_string());
+ }
+
let head_elements = match head.element() {
Some(ok) => ok,
None => {
@@ -166,6 +172,7 @@ pub async fn build_ui(
}
}
+ //css is pushed to css variable inside render_head()
css.push_str(&html_view.style());
for element in body_elements.children.iter() {
@@ -210,12 +217,22 @@ pub async fn build_ui(
let tagss = Rc::clone(&tags);
if !src.is_empty() {
- let luacode = if src.starts_with("https://") {
- fetch_file(src).await
+
+ let src_clone = src.clone();
+
+ let luacode = if src_clone.starts_with("https://") {
+ fetch_file(src_clone).await
} else {
- fetch_file(format!("{}/{}", furl, src)).await
+ fetch_file(format!("{}/{}", furl, src_clone)).await
};
+ //add lua code to page source
+ {
+ let src_clone = src.clone();
+ let mut page_source = tab.page_source.borrow_mut();
+ page_source.add_file(src_clone.to_string(), luacode.to_string());
+ }
+
if let Err(e) = super::lua::run(luacode, tags, tab.url.clone()).await {
println!("ERROR: Failed to run lua: {}", e);
}
@@ -274,6 +291,11 @@ async fn render_head(element: &Element, contents: Option<&Node>, tab: Rc>,
// id: String,
}
@@ -149,6 +152,13 @@ fn handle_search_update(
tab_in_closure.url = dns_url;
}
+ {
+ //clear page_source info for tab before fetching new page files
+ //enclosed to let borrowed mut go out of scope
+ let mut page_source_in_closure = tab_in_closure.page_source.borrow_mut();
+ page_source_in_closure.clear();
+ }
+
searchbar_mut.set_text(&url.replace("buss://", ""));
searchbar_mut.set_position(-1);
@@ -186,6 +196,7 @@ fn get_time() -> String {
fn build_ui(app: &adw::Application, args: Rc>>, config: Rc>) {
let history = Rc::new(RefCell::new(History::new()));
+ let page_source = Rc::new(RefCell::new(PageSource::new()));
let default_url = if let Some(dev_build) = args.borrow().get(1) { // cli
dev_build.to_string()
@@ -221,7 +232,8 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc>>, config: Rc> = Rc::new(RefCell::new(app.clone()));
let event_controller = gtk::EventControllerKey::new();
let history_ = Rc::clone(&history);
+ let page_source_ = Rc::clone(&page_source);
+
+ // let lua_logs_showing = Rc::new(RefCell::new(false));
+ // let settings_showing = Rc::new(RefCell::new(false));
+ // let history_showing = Rc::new(RefCell::new(false));
+
+ let source_viewer_showing = Rc::new(RefCell::new(false));
+ let source_viewer_window: Rc>> = Rc::new(RefCell::new(None));
+
+ let source_viewer_showing_ = source_viewer_showing.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
event_controller.connect_key_pressed(move |_, key, _a, b| {
let app_clone = Rc::clone(&app_);
let history_clone = Rc::clone(&history_);
+ let page_source_clone = Rc::clone(&page_source_);
+
+ let source_viewer_showing_clone = source_viewer_showing_.clone();
+ let mut source_viewer_window_ref = source_viewer_window_.borrow_mut();
if b == (gdk::ModifierType::SHIFT_MASK | gdk::ModifierType::CONTROL_MASK)
&& key == gdk::Key::P
@@ -284,6 +311,17 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc>>, config: Rc>>, config: Rc> = Rc::new(RefCell::new(app.clone()));
search.connect_activate({
+ let rc_scroll_search = rc_scroll.clone();
+ let rc_css_provider_search = rc_css_provider.clone();
+ let rc_tab_search = rc_tab.clone();
let history = history.clone();
let go_forward = go_forward.clone();
let go_back = go_back.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
+ let source_viewer_showing_= source_viewer_showing.clone();
+ let page_source_ = page_source.clone();
+
move |query| {
update_buttons(&go_back, &go_forward, &history);
handle_search_update(
@@ -348,18 +394,33 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc> = Rc::new(RefCell::new(app.clone()));
refresh_button.connect_clicked({
+ let rc_scroll_refresh = rc_scroll.clone();
+ let rc_css_provider_refresh = rc_css_provider.clone();
+ let rc_tab_refresh = rc_tab.clone();
+ let rc_search_refresh = rc_search.clone();
let history = history.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
+ let source_viewer_showing_= source_viewer_showing.clone();
+ let page_source_ = page_source.clone();
history
.borrow_mut()
.add_to_history(rc_search_refresh.borrow().text().to_string(), get_time(), true);
@@ -370,17 +431,32 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc> = Rc::new(RefCell::new(app.clone()));
home_button.connect_clicked({
- let history = history.clone();
+ let rc_scroll_home = rc_scroll.clone();
+ let rc_css_provider_home = rc_css_provider.clone();
+ let rc_tab_home = rc_tab.clone();
+ let rc_search_home = rc_search.clone();
+ let history = history.clone();
let go_forward = go_forward.clone();
let go_back = go_back.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
+ let source_viewer_showing_= source_viewer_showing.clone();
+ let page_source_ = page_source.clone();
move |_button| {
rc_search_home.borrow_mut().set_text(DEFAULT_URL);
history
@@ -393,17 +469,32 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc> = Rc::new(RefCell::new(app.clone()));
go_back.connect_clicked({
+ let rc_scroll_back = rc_scroll.clone();
+ let rc_css_provider_back = rc_css_provider.clone();
+ let rc_tab_back = rc_tab.clone();
+ let rc_search_back = rc_search.clone();
let history = history.clone();
let go_forward = go_forward.clone();
let go_back = go_back.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
+ let source_viewer_showing_= source_viewer_showing.clone();
+ let page_source_ = page_source.clone();
move |_| {
history.borrow_mut().go_back();
update_buttons(&go_back, &go_forward, &history);
@@ -415,30 +506,153 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc> = Rc::new(RefCell::new(app.clone()));
go_forward.connect_clicked({
+ let rc_scroll_forward = rc_scroll.clone();
+ let rc_css_provider_forward = rc_css_provider.clone();
+ let rc_tab_forward = rc_tab.clone();
+ let rc_search_forward = rc_search.clone();
let history = history.clone();
let go_forward = go_forward.clone();
let go_back = go_back.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
+ let source_viewer_showing_= source_viewer_showing.clone();
+ let page_source_ = page_source.clone();
move |_| {
history.borrow_mut().go_forward();
update_buttons(&go_back, &go_forward, &history);
let current_url = history.borrow().current().unwrap().url.clone();
- rc_search.borrow_mut().set_text(¤t_url);
+ rc_search_forward.borrow_mut().set_text(¤t_url);
handle_search_update(
rc_scroll_forward.clone(),
rc_css_provider_forward.clone(),
- rc_tab.clone(),
- rc_search.clone(),
+ rc_tab_forward.clone(),
+ rc_search_forward.clone(),
);
+ //If open, refresh source viewer on new page
+ if *source_viewer_showing_.clone().borrow_mut() {
+ let mut source_viewer_window_ref = source_viewer_window_.borrow_mut();
+ let page_source_clone = Rc::clone(&page_source_);
+ let app_clone = app_.clone();
+
+ if let Some(ref window) = *source_viewer_window_ref{
+ window.close();
+ *source_viewer_window_ref = Some(display_source_viewer(&app_clone, page_source_clone, source_viewer_showing_.clone()));
+ }
+ }
}
});
- glib::source::timeout_add_local(std::time::Duration::from_millis(5000), move || { // every 5 seconds remove "stale" timeouts
+ //mouse button listeners for forward/back page navigation
+ //mouse back - button "8"
+ let gesture_back = gtk::GestureClick::new();
+ gesture_back.set_button(8);
+
+ let app_: Rc> = Rc::new(RefCell::new(app.clone()));
+ gesture_back.connect_pressed({
+ let rc_scroll_back = rc_scroll.clone();
+ let rc_css_provider_back = rc_css_provider.clone();
+ let rc_tab_back = rc_tab.clone();
+ let rc_search_back = rc_search.clone();
+ let history = history.clone();
+ let go_forward = go_forward.clone();
+ let go_back = go_back.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
+ let source_viewer_showing_= source_viewer_showing.clone();
+ let page_source_ = page_source.clone();
+ move |gesture_back, n, _x, _y| {
+ gesture_back.set_state(gtk::EventSequenceState::Claimed);
+
+ if n < 2 {
+ history.borrow_mut().go_back();
+ update_buttons(&go_back, &go_forward, &history);
+ let current_url = history.borrow().current().unwrap().url.clone();
+ rc_search_back.borrow_mut().set_text(¤t_url);
+ handle_search_update(
+ rc_scroll_back.clone(),
+ rc_css_provider_back.clone(),
+ rc_tab_back.clone(),
+ rc_search_back.clone(),
+ );
+ //If open, refresh source viewer on new page
+ if *source_viewer_showing_.clone().borrow_mut() {
+ let mut source_viewer_window_ref = source_viewer_window_.borrow_mut();
+ let page_source_clone = Rc::clone(&page_source_);
+ let app_clone = app_.clone();
+
+ if let Some(ref window) = *source_viewer_window_ref{
+ window.close();
+ *source_viewer_window_ref = Some(display_source_viewer(&app_clone, page_source_clone, source_viewer_showing_.clone()));
+ }
+ }
+ }
+ }});
+
+ window.add_controller(gesture_back);
+
+ //mouse forward - button "9"
+ let gesture_forward = gtk::GestureClick::new();
+ gesture_forward.set_button(9);
+
+ let app_: Rc> = Rc::new(RefCell::new(app.clone()));
+ gesture_forward.connect_pressed({
+ let rc_scroll_forward = rc_scroll.clone();
+ let rc_css_provider_forward = rc_css_provider.clone();
+ let rc_tab_forward = rc_tab.clone();
+ let rc_search_forward = rc_search.clone();
+ let history = history.clone();
+ let go_forward = go_forward.clone();
+ let go_back = go_back.clone();
+ let source_viewer_window_ = source_viewer_window.clone();
+ let source_viewer_showing_= source_viewer_showing.clone();
+ let page_source_ = page_source.clone();
+ move |gesture_forward, n, _x, _y|{
+
+ gesture_forward.set_state(gtk::EventSequenceState::Claimed);
+
+ if n < 2 {
+ history.borrow_mut().go_forward();
+ update_buttons(&go_back, &go_forward, &history);
+ let current_url = history.borrow().current().unwrap().url.clone();
+ rc_search_forward.borrow_mut().set_text(¤t_url);
+ handle_search_update(
+ rc_scroll_forward.clone(),
+ rc_css_provider_forward.clone(),
+ rc_tab_forward.clone(),
+ rc_search_forward.clone()
+ );
+ //If open, refresh source viewer on new page
+ if *source_viewer_showing_.clone().borrow_mut() {
+ let mut source_viewer_window_ref = source_viewer_window_.borrow_mut();
+ let page_source_clone = Rc::clone(&page_source_);
+ let app_clone = app_.clone();
+
+ if let Some(ref window) = *source_viewer_window_ref{
+ window.close();
+ *source_viewer_window_ref = Some(display_source_viewer(&app_clone, page_source_clone, source_viewer_showing_.clone()));
+ }
+ }
+ }
+ }});
+
+ window.add_controller(gesture_forward);
+
+ // every 5 seconds remove "stale" timeouts
+ glib::source::timeout_add_local(std::time::Duration::from_millis(5000), move || {
let mut timeouts = LUA_TIMEOUTS.lock().unwrap();
timeouts.retain(|source| {
!source.is_destroyed()
@@ -447,6 +661,10 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc>, css_provider: Rc>){
+
+// }
+
// commented code here was an attempt at implementing multiple tabs.
// it will be kept here in case I decide to implement multiple tabs again
fn make_tab(
@@ -456,6 +674,7 @@ fn make_tab(
// cursor_pointer: Option<&Cursor>,
mut tabs: Vec,
default_url: String,
+ page_source: Rc>,
) -> Tab {
// let tabid = gen_tab_id();
@@ -517,6 +736,7 @@ fn make_tab(
// id: tabid,
label_widget: tabname,
icon_widget: tabicon,
+ page_source: page_source
};
tabs.push(res.clone());
@@ -611,7 +831,16 @@ fn fetch_dns(url: String) -> String {
if let Ok(json) = response.json::() {
let path = url.split_once('/')
.unwrap_or(("", "")).1;
- json.ip + &format!("/{}", path)
+
+ //check if json.ip is a standalone IP address,
+ //if so, prepend "http://" to make it parsable
+ //as a url.
+ let ip = match json.ip.parse::() {
+ Ok(_ip) => format!("http://{}", json.ip),
+ Err(_) => json.ip.clone(),
+ };
+
+ ip + &format!("/{}", path)
} else {
lualog!(
"debug",
@@ -628,6 +857,96 @@ fn fetch_dns(url: String) -> String {
}
}
+fn display_source_viewer(app: &Rc>, page_source: Rc>, showing: Rc>) -> Window{
+
+ let window: Window = Object::builder()
+ .property("application", glib::Value::from(&*app.borrow_mut()))
+ .build();
+
+ window.set_default_size(800, 900);
+ window.set_height_request(500);
+ window.set_width_request(800);
+
+ // Create the main container box with horizontal orientation
+ let main_box = gtk::Box::builder()
+ .orientation(gtk::Orientation::Horizontal)
+ .spacing(6)
+ .margin_top(6)
+ .margin_bottom(6)
+ .margin_start(6)
+ .margin_end(6)
+ .build();
+
+ // Create the menu box for the left side
+ let menu_box = gtk::Box::builder()
+ .orientation(gtk::Orientation::Vertical)
+ .spacing(6)
+ .width_request(140)
+ .build();
+
+ // scroller for text area
+ let content_scroll = gtk::ScrolledWindow::builder().build();
+
+ let content_text_view = gtk::TextView::builder()
+ .wrap_mode(gtk::WrapMode::Word)
+ .editable(false)
+ .hexpand(true)
+ .build();
+
+ content_scroll.set_child(Some(&content_text_view));
+
+ // let files = page_source.get_files();
+
+ // create buffers and listeners to update the text area buffer
+ let content_buffer = content_text_view.buffer();
+
+ for file in page_source.borrow().get_files() {
+
+ let button = gtk::Button::with_label(file.get(0).expect(""));
+
+ let file_clone = file.clone();
+
+ button.connect_clicked({
+ let content_buffer = content_buffer.clone();
+
+ move |_| {
+ content_buffer.set_text(file_clone.get(1).expect(""));
+ }
+ });
+
+ menu_box.append(&button);
+ }
+
+ // Add menu box and content area to the main box
+ main_box.append(&menu_box);
+ main_box.append(&content_scroll);
+
+ window.set_child(Some(&main_box));
+
+ let label = gtk::Label::new(Some("Source"));
+ let empty_label = gtk::Label::new(Some(""));
+ let headerbar = gtk::HeaderBar::builder().build();
+
+ headerbar.pack_start(&label);
+ headerbar.set_title_widget(Some(&empty_label));
+
+ window.set_titlebar(Some(&headerbar));
+
+ let showing_clone = showing.clone();
+ window.connect_close_request(move |_|{
+
+ *showing_clone.borrow_mut() = false;
+
+ gtk::glib::Propagation::Proceed
+ });
+
+ window.present();
+
+ *showing.borrow_mut() = true;
+
+ window
+}
+
fn display_lua_logs(app: &Rc>) {
let window: Window = Object::builder()
.property("application", glib::Value::from(&*app.borrow_mut()))
diff --git a/napture/src/page_source_mod/mod.rs b/napture/src/page_source_mod/mod.rs
new file mode 100644
index 00000000..e7d37124
--- /dev/null
+++ b/napture/src/page_source_mod/mod.rs
@@ -0,0 +1,25 @@
+#[derive(Debug)]
+pub struct PageSource {
+ files: Vec>,
+}
+
+impl PageSource {
+ pub fn new() -> Self {
+ PageSource {
+ files: Vec::new(),
+ }
+ }
+
+ pub fn add_file(&mut self, name: String, contents: String){
+ let file = vec![name, contents];
+ self.files.push(file);
+ }
+
+ pub fn get_files(&self) -> &Vec>{
+ &self.files
+ }
+
+ pub fn clear(&mut self){
+ self.files.clear();
+ }
+}
\ No newline at end of file