>();
754 |
755 | let softhidden_entries_container = document
756 | .get_element_by_id("softhidden-entries-container")
757 | .unwrap();
758 |
759 | let mut index_of_athing = 0;
760 |
761 | for text_of_sidebar_item in list_of_titlelines_to_softhide
762 | {
763 | let mut count_of_filtered_entries: &mut (u32, u32, u32, u32) = &mut (0, 0, 0, 0);
764 |
765 | for titleline_span in &list_of_titleline_spans_as_rust
766 | {
767 | hide_specific_item_of_a_specific_category(
768 | &"Title".to_owned(),
769 | &text_of_sidebar_item,
770 | &titleline_span,
771 | "Title",
772 | count_of_filtered_entries,
773 | );
774 | }
775 |
776 | let document = obtain_document();
777 |
778 | let softhidden_entry_in_sidebar_div = document
779 | .create_element("div")
780 | .unwrap();
781 |
782 | let softhidden_entry_in_sidebar_div: Element = softhidden_entry_in_sidebar_div
783 | .dyn_into()
784 | .unwrap();
785 |
786 | softhidden_entry_in_sidebar_div
787 | .set_attribute("class", "softhidden-entry")
788 | .unwrap();
789 |
790 | softhidden_entry_in_sidebar_div
791 | .set_attribute("style", "position: relative; clear: both; float: left; box-sizing: border-box; width: 100%; border-radius: 4px; background-color: #f6f6ef; padding: 3px; margin-bottom: 6px; font-size:0.6rem"
792 | );
793 |
794 | let athing_id = list_of_athing_ids_to_softhide[index_of_athing].clone();
795 |
796 | softhidden_entry_in_sidebar_div.set_inner_html(
797 | &format!(
798 | r###"
799 | ⨯
800 | {text_of_sidebar_item}
801 | "###
802 | )
803 | );
804 |
805 | softhidden_entry_in_sidebar_div.set_attribute("id", &format!("container-{athing_id}"));
806 |
807 | &softhidden_entries_container
808 | .append_child(&softhidden_entry_in_sidebar_div)
809 | .unwrap();
810 |
811 | let softhidden_entries_container_clone = softhidden_entries_container.clone();
812 |
813 | let exclude_softhidden_button = &document
814 | .get_element_by_id(&format!("softhidden-{athing_id}"))
815 | .unwrap();
816 |
817 | let exclude_softhidden_button: Element = exclude_softhidden_button
818 | .clone()
819 | .dyn_into()
820 | .unwrap();
821 |
822 | let listener = EventListener::new(&exclude_softhidden_button, "click", move |event: &Event| {
823 |
824 | let local_storage = web_sys::window()
825 | .unwrap()
826 | .local_storage()
827 | .unwrap()
828 | .unwrap();
829 |
830 | let athing_id_to_submission_title_as_string = local_storage
831 | .get_item("softhidden_things")
832 | .unwrap()
833 | .unwrap_or_else(
834 | || {
835 | "{}".to_owned()
836 | },
837 | );
838 |
839 | let mut athing_id_to_submission_title: serde_json::Value =
840 | serde_json::from_str(&athing_id_to_submission_title_as_string).unwrap();
841 |
842 | if let Some(obj) = athing_id_to_submission_title.as_object_mut() {
843 | obj.remove(&athing_id.to_string()); // This line modifies `value` in place
844 | }
845 |
846 | let amended_athing_id_to_submission_title_as_string = serde_json::to_string(&athing_id_to_submission_title);
847 |
848 |
849 | match amended_athing_id_to_submission_title_as_string {
850 | Ok(stringified_json) => {
851 | write_athing_id_to_submission_title_as_stringified_json_to_local_storage(&stringified_json);
852 | }
853 | Err(e) => { }
854 | }
855 |
856 | if let Some(submission_to_unhide_tr) =
857 | &document.get_element_by_id(&athing_id)
858 | {
859 | submission_to_unhide_tr.set_attribute("style", "");
860 |
861 | if let Some(subtext_tr) = submission_to_unhide_tr.next_element_sibling()
862 | {
863 | subtext_tr.set_attribute("style", "");
864 |
865 |
866 | if let Some(spacer_tr) = subtext_tr.next_element_sibling()
867 | {
868 | spacer_tr.set_attribute("style", "");
869 | }
870 | }
871 | }
872 |
873 | let document_clone = obtain_document();
874 |
875 | let softhidden_entries_container_here = document_clone
876 | .get_element_by_id("softhidden-entries-container")
877 | .unwrap();
878 |
879 |
880 |
881 | let softhidden_entry_in_sidebar_div = document_clone
882 | .get_element_by_id(&format!("container-{athing_id}"))
883 | .unwrap();
884 |
885 |
886 | softhidden_entries_container_here.remove_child(&softhidden_entry_in_sidebar_div);
887 |
888 | });
889 |
890 | listener.forget();
891 |
892 |
893 | index_of_athing += 1;
894 |
895 | }
896 |
897 | for text_of_sidebar_item in filter_summary_texts
898 | {
899 | iteration += 1;
900 |
901 | let document = obtain_document();
902 |
903 | let filter_container_div = document
904 | .create_element("div")
905 | .unwrap();
906 |
907 | let filter_container_div_as_el: Element = filter_container_div
908 | .dyn_into()
909 | .unwrap();
910 |
911 | filter_container_div_as_el
912 | .set_attribute(
913 | "class",
914 | &format!("filter-item-wrapper"),
915 | )
916 | .unwrap();
917 |
918 | let filter_summary_div = document
919 | .create_element("div")
920 | .unwrap();
921 |
922 | let filter_summary_div: Element = filter_summary_div
923 | .dyn_into()
924 | .unwrap();
925 |
926 | filter_summary_div
927 | .set_attribute("class", "filter-item-keyword-wrapper")
928 | .unwrap();
929 |
930 | filter_summary_div.set_inner_html(
931 | &format!(
932 | r###"
933 |
934 |
938 | "###
939 | )
940 | );
941 |
942 | filter_container_div_as_el
943 | .append_child(&filter_summary_div)
944 | .unwrap();
945 |
946 | let radiobuttons_holder = format!(
947 | r###"
948 | ⨯
949 |
950 |
951 |
958 |
959 |
960 |
961 |
968 |
969 |
970 |
971 |
978 |
979 |
986 | "###);
987 |
988 | let inner_html_of_fitler_container_div_as_el = filter_container_div_as_el.inner_html();
989 |
990 | filter_container_div_as_el.set_inner_html(&format!(
991 | "{inner_html_of_fitler_container_div_as_el} {radiobuttons_holder}"
992 | ));
993 |
994 | let sidebar_items_container = document
995 | .get_element_by_id("filter-items-container")
996 | .unwrap();
997 |
998 | sidebar_items_container
999 | .append_child(&filter_container_div_as_el)
1000 | .unwrap();
1001 |
1002 | let filter_target_text = filter_summary_text_to_filter_target_text
1003 | .get(&text_of_sidebar_item)
1004 | .unwrap();
1005 |
1006 | // ----------------------------
1007 | // ----------------------------
1008 | // ----------------------------
1009 |
1010 | let mut count_of_filtered_entries: &mut (u32, u32, u32, u32) = &mut (0, 0, 0, 0);
1011 |
1012 | for titleline_span in &list_of_titleline_spans_as_rust
1013 | {
1014 | hide_specific_item_of_a_specific_category(
1015 | filter_target_text,
1016 | &text_of_sidebar_item,
1017 | &titleline_span,
1018 | "Title",
1019 | count_of_filtered_entries,
1020 | );
1021 | }
1022 |
1023 | // ----------------------------
1024 | // ----------------------------
1025 | // ----------------------------
1026 |
1027 | for link in &list_of_links_as_rust
1028 | {
1029 | hide_specific_item_of_a_specific_category(
1030 | filter_target_text,
1031 | &text_of_sidebar_item,
1032 | &link,
1033 | "Link",
1034 | count_of_filtered_entries,
1035 | );
1036 | }
1037 |
1038 | // ----------------------------
1039 | // ----------------------------
1040 | // ----------------------------
1041 |
1042 | for username in &list_of_hnusers_as_rust
1043 | {
1044 | hide_specific_item_of_a_specific_category(
1045 | filter_target_text,
1046 | &text_of_sidebar_item,
1047 | &username,
1048 | "Username",
1049 | count_of_filtered_entries,
1050 | );
1051 | }
1052 |
1053 | // ----------------------------
1054 | // ----------------------------
1055 | // ----------------------------
1056 |
1057 | for comment in &list_of_comments_as_rust
1058 | {
1059 | hide_specific_item_of_a_specific_category(
1060 | filter_target_text,
1061 | &text_of_sidebar_item,
1062 | &comment,
1063 | "Comment",
1064 | count_of_filtered_entries,
1065 | );
1066 | }
1067 |
1068 | let (
1069 | count_of_filtered_entries_0,
1070 | count_of_filtered_entries_1,
1071 | count_of_filtered_entries_2,
1072 | count_of_filtered_entries_3,
1073 | ) = count_of_filtered_entries;
1074 |
1075 | let radiobuttons_holder_2 = format!(
1076 | r#"
1077 | {count_of_filtered_entries_0}/{count_of_filtered_entries_1}/{count_of_filtered_entries_2}/{count_of_filtered_entries_3}
1078 | "#);
1079 |
1080 | let filter_items_container = document
1081 | .get_element_by_id("filter-items-container")
1082 | .unwrap();
1083 |
1084 | let filter_container_div_as_el_with_proper_radiobutton_set = filter_items_container
1085 | .last_child()
1086 | .unwrap();
1087 |
1088 | let filter_container_div_as_el_with_proper_radiobutton_set_as_el: Element = filter_container_div_as_el_with_proper_radiobutton_set
1089 | .dyn_into()
1090 | .unwrap();
1091 |
1092 | let inner_html_of_fitler_container_div_as_el = filter_container_div_as_el_with_proper_radiobutton_set_as_el.inner_html();
1093 |
1094 | filter_container_div_as_el_with_proper_radiobutton_set_as_el.set_inner_html(&format!(
1095 | "{inner_html_of_fitler_container_div_as_el} {radiobuttons_holder_2}"
1096 | ));
1097 |
1098 |
1099 | if filter_target_text.contains("Title")
1100 | {
1101 | set_specific_radiobutton_for_category_as_checked(
1102 | &filter_container_div_as_el_with_proper_radiobutton_set_as_el,
1103 | "title",
1104 | iteration,
1105 | );
1106 | }
1107 | if filter_target_text.contains("Link")
1108 | {
1109 | set_specific_radiobutton_for_category_as_checked(
1110 | &filter_container_div_as_el_with_proper_radiobutton_set_as_el,
1111 | "link",
1112 | iteration,
1113 | );
1114 | }
1115 |
1116 | if filter_target_text.contains("Username")
1117 | {
1118 | set_specific_radiobutton_for_category_as_checked(
1119 | &filter_container_div_as_el_with_proper_radiobutton_set_as_el,
1120 | "username",
1121 | iteration,
1122 | );
1123 | }
1124 |
1125 | if filter_target_text.contains("Comment")
1126 | {
1127 | set_specific_radiobutton_for_category_as_checked(
1128 | &filter_container_div_as_el_with_proper_radiobutton_set_as_el,
1129 | "comment",
1130 | iteration,
1131 | );
1132 | }
1133 | }
1134 |
1135 | Ok(())
1136 | }
1137 |
1138 | pub fn set_specific_radiobutton_for_category_as_checked(
1139 | filter_container_div_as_el: &Element,
1140 | category_str: &str,
1141 | iteration: usize,
1142 | )
1143 | {
1144 | let radiobutton_as_rust = filter_container_div_as_el
1145 | .query_selector(&format!("#cb-{category_str}-keywords-{iteration}"))
1146 | .unwrap();
1147 |
1148 | let radiobutton_as_el: Element = radiobutton_as_rust
1149 | .unwrap()
1150 | .dyn_into()
1151 | .unwrap();
1152 |
1153 | let radiobutton_as_radiobutton: HtmlInputElement = radiobutton_as_el
1154 | .dyn_into()
1155 | .unwrap();
1156 |
1157 | radiobutton_as_radiobutton.set_checked(true);
1158 | }
1159 |
--------------------------------------------------------------------------------
/src/getters.rs:
--------------------------------------------------------------------------------
1 | use wasm_bindgen::prelude::*;
2 | use web_sys::{
3 | Document,
4 | Element,
5 | Event,
6 | *,
7 | };
8 | use indexmap::IndexMap;
9 | use wasm_bindgen::JsCast;
10 |
11 | use gloo_console::log as gloo_log;
12 |
13 | #[wasm_bindgen]
14 | pub fn obtain_document() -> Document
15 | {
16 | let window = web_sys::window().expect("no global `window` exists");
17 |
18 | window
19 | .document()
20 | .expect("should have a document on window")
21 | }
22 |
23 | pub fn obtain_filter_summary_text_to_filter_target_text_from_local_storage(
24 | ) -> IndexMap
25 | {
26 | let local_storage = web_sys::window()
27 | .unwrap()
28 | .local_storage()
29 | .unwrap()
30 | .unwrap();
31 |
32 | let hackernew_userscript_data_as_string_option = local_storage
33 | .get_item("hackernews_userscript")
34 | .unwrap()
35 | .unwrap_or_else(
36 | || {
37 | let stringified_json_with_single_key = "{\"sidebar_items\": []}";
38 |
39 | local_storage
40 | .set_item("hackernews_userscript", &stringified_json_with_single_key)
41 | .unwrap();
42 |
43 | stringified_json_with_single_key.to_owned()
44 | },
45 | );
46 |
47 | let hackernew_userscript_data_as_string = hackernew_userscript_data_as_string_option;
48 |
49 | let hackernew_userscript_data_as_json: serde_json::Value =
50 | serde_json::from_str(&hackernew_userscript_data_as_string).unwrap();
51 |
52 | let sidebar_items_as_json = hackernew_userscript_data_as_json
53 | .as_object()
54 | .unwrap()
55 | .get("sidebar_items")
56 | .unwrap();
57 |
58 | let sidebar_items_as_vec_of_tuples_with_two_strings: Vec<(String, String)> =
59 | serde_json::from_value(sidebar_items_as_json.clone()).unwrap();
60 |
61 | let sidebar_items_as_indexmap: IndexMap =
62 | sidebar_items_as_vec_of_tuples_with_two_strings
63 | .into_iter()
64 | .collect();
65 |
66 | sidebar_items_as_indexmap
67 | }
68 |
69 | pub fn obtain_settings_from_local_storage(
70 | ) -> serde_json::Value
71 | {
72 | let local_storage = web_sys::window()
73 | .unwrap()
74 | .local_storage()
75 | .unwrap()
76 | .unwrap();
77 |
78 | let settings_as_string_option = local_storage
79 | .get_item("settings")
80 | .unwrap()
81 | .unwrap_or_else(
82 | || {
83 | let stringified_json_with_single_key = "{}";
84 |
85 | local_storage
86 | .set_item("settings", &stringified_json_with_single_key)
87 | .unwrap();
88 |
89 | stringified_json_with_single_key.to_owned()
90 | },
91 | );
92 |
93 | let settings_as_string = settings_as_string_option;
94 |
95 | let settings_as_json: serde_json::Value =
96 | serde_json::from_str(&settings_as_string).unwrap();
97 |
98 | settings_as_json
99 | }
100 |
101 | pub fn obtain_list_of_titleline_spans_as_rust_list_of_links_as_rust_list_of_hnusers_as_rust(
102 | ) -> Result<(Vec, Vec, Vec, Vec), JsValue>
103 | {
104 | let document = obtain_document();
105 |
106 | let body = document
107 | .get_elements_by_tag_name("body")
108 | .get_with_index(0)
109 | .ok_or_else(|| JsValue::from_str("No body element found"))?;
110 |
111 | let list_of_titleline_spans_as_js = body.query_selector_all(".athing .titleline")?;
112 |
113 | let list_of_titleline_spans_as_rust: Vec = (0..list_of_titleline_spans_as_js.length())
114 | .map(|index| {
115 | list_of_titleline_spans_as_js
116 | .item(index)
117 | .ok_or_else(|| JsValue::from_str("Missing element at index"))
118 | .and_then(|item| {
119 | item.dyn_into::()
120 | .map_err(|_| JsValue::from_str("Failed to cast to Element"))
121 | })
122 | })
123 | .collect::>()?;
124 |
125 | let list_of_links_as_rust = list_of_titleline_spans_as_rust
126 | .iter()
127 | .map(|titleline_span| {
128 | titleline_span
129 | .query_selector("a")
130 | .map_err(|_| JsValue::from_str("Failed to query_selector for 'a'"))?
131 | .ok_or_else(|| JsValue::from_str("No 'a' element found"))
132 | .and_then(|link| {
133 | link.dyn_into::()
134 | .map_err(|_| JsValue::from_str("Failed to cast to Element"))
135 | })
136 | })
137 | .collect::>()?;
138 |
139 | let list_of_hnusers_as_js = body.query_selector_all(".hnuser")?;
140 |
141 | let list_of_hnusers_as_rust: Vec = (0..list_of_hnusers_as_js.length())
142 | .map(|index| {
143 | list_of_hnusers_as_js
144 | .item(index)
145 | .ok_or_else(|| JsValue::from_str("Missing hnuser at index"))
146 | .and_then(|item| {
147 | item.dyn_into::()
148 | .map_err(|_| JsValue::from_str("Failed to cast to Element"))
149 | })
150 | })
151 | .collect::>()?;
152 |
153 | let list_of_comments_as_js = body.query_selector_all(".commtext")?;
154 |
155 | let list_of_comments_as_rust: Vec = (0..list_of_comments_as_js.length())
156 | .map(|index| {
157 | list_of_comments_as_js
158 | .item(index)
159 | .ok_or_else(|| JsValue::from_str("Missing comment at index"))
160 | .and_then(|item| {
161 | item.dyn_into::()
162 | .map_err(|_| JsValue::from_str("Failed to cast to Element"))
163 | })
164 | })
165 | .collect::>()?;
166 |
167 | Ok(
168 | (
169 | list_of_titleline_spans_as_rust,
170 | list_of_links_as_rust,
171 | list_of_comments_as_rust,
172 | list_of_hnusers_as_rust,
173 | )
174 | )
175 | }
176 |
177 | fn value_to_indexmap(value: &serde_json::Value) -> Option> {
178 | let mut map = IndexMap::new();
179 |
180 | if let serde_json::Value::Object(obj) = value {
181 | for (key, val) in obj {
182 | let key_str = key.to_string();
183 | let val_str = val.as_str().unwrap_or("").to_string();
184 | map.insert(key_str, val_str);
185 | }
186 | Some(map)
187 | } else {
188 | None
189 | }
190 | }
191 |
192 |
193 | pub fn obtain_athing_id_to_submission_title_from_local_storage(
194 | ) -> IndexMap
195 | {
196 | let local_storage = web_sys::window()
197 | .unwrap()
198 | .local_storage()
199 | .unwrap()
200 | .unwrap();
201 |
202 | let athing_id_to_submission_title_as_string_option = local_storage
203 | .get_item("softhidden_things")
204 | .unwrap()
205 | .unwrap_or_else(
206 | || {
207 | let stringified_json_with_single_key = "{}";
208 |
209 | local_storage
210 | .set_item("softhidden_things", &stringified_json_with_single_key)
211 | .unwrap();
212 |
213 | stringified_json_with_single_key.to_owned()
214 | },
215 | );
216 |
217 | let athing_id_to_submission_title_as_string = athing_id_to_submission_title_as_string_option;
218 |
219 | let athing_id_to_submission_title_as_json: serde_json::Value =
220 | serde_json::from_str(&athing_id_to_submission_title_as_string).unwrap();
221 |
222 | let athing_id_to_submission_title_indexmap: IndexMap =
223 | value_to_indexmap(&athing_id_to_submission_title_as_json).unwrap();
224 |
225 | athing_id_to_submission_title_indexmap
226 | }
227 |
228 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | use base64;
2 | use wasm_bindgen::prelude::*;
3 | use web_sys::*;
4 | #[macro_use]
5 | mod util;
6 | use std::iter::Iterator;
7 | use std::collections::HashMap;
8 |
9 | use indexmap::IndexMap;
10 | use serde_json::{json, Value, to_string};
11 | use regex::Regex;
12 | use wasm_bindgen::JsCast;
13 | use gloo_console::log as gloo_log;
14 | use gloo::events::EventListener;
15 | use web_sys::{
16 | Document,
17 | Element,
18 | Event,
19 | HtmlButtonElement,
20 | KeyboardEvent,
21 | HtmlInputElement,
22 | HtmlImageElement,
23 | };
24 |
25 | mod getters;
26 | use getters::{
27 | obtain_document,
28 | obtain_filter_summary_text_to_filter_target_text_from_local_storage,
29 | obtain_list_of_titleline_spans_as_rust_list_of_links_as_rust_list_of_hnusers_as_rust,
30 | };
31 |
32 | mod setters;
33 | use setters::{
34 | write_sidebar_items_as_stringified_json_to_local_storage,
35 | write_athing_id_to_submission_title_as_stringified_json_to_local_storage,
36 | };
37 |
38 | mod dom_manipulation;
39 | use dom_manipulation::{
40 | hide_specific_item_of_a_specific_category,
41 | load_items_from_locastorage_populate_sidebar_and_apply_filters,
42 | parse_string_with_css_and_insert_into_header,
43 | parse_string_with_sidebar_and_insert_into_body,
44 | remove_all_children_of_filter_items_container,
45 | replace_center_tag_with_div,
46 | select_submission_elements_and_set_their_style,
47 | set_specific_radiobutton_for_category_as_checked,
48 | };
49 |
50 | mod pure;
51 | use pure::stringify_filter_summary_text_to_filter_target_text_from_map;
52 |
53 | #[wasm_bindgen]
54 | pub fn register_sidebar_item_event_listener() -> Result<(), JsValue>
55 | {
56 | let document = obtain_document();
57 |
58 | let body = document
59 | .get_elements_by_tag_name("body")
60 | .get_with_index(0)
61 | .unwrap();
62 |
63 | let result =
64 | obtain_list_of_titleline_spans_as_rust_list_of_links_as_rust_list_of_hnusers_as_rust();
65 | let (
66 | list_of_titleline_spans_as_rust,
67 | list_of_links_as_rust,
68 | list_of_comments_as_rust,
69 | list_of_hnusers_as_rust,
70 | ) =
71 | match result
72 | {
73 | | Ok(value) => value,
74 | | Err(err) => return Err(err),
75 | };
76 |
77 | let sidebar_container = &document
78 | .get_element_by_id("filter-items-container")
79 | .unwrap();
80 |
81 | let sidebar_container: Element = sidebar_container
82 | .clone()
83 | .dyn_into()?;
84 |
85 | let document_ref = document;
86 |
87 | let list_of_titleline_spans_as_rust_ref = list_of_titleline_spans_as_rust;
88 |
89 | let listener = EventListener::new(&sidebar_container, "click", move |event: &Event| {
90 | let ic_remove_or_filter_selector_wrapper = event
91 | .target()
92 | .unwrap();
93 |
94 | if let Ok(ic_remove_or_filter_selector_wrapper) =
95 | ic_remove_or_filter_selector_wrapper.dyn_into::()
96 | {
97 | match ic_remove_or_filter_selector_wrapper
98 | .class_name()
99 | .as_str()
100 | {
101 | | "ic-remove" =>
102 | {
103 | let filter_item_wrapper = ic_remove_or_filter_selector_wrapper
104 | .parent_node()
105 | .unwrap();
106 |
107 | let filter_item_keyword_wrapper = filter_item_wrapper
108 | .first_child()
109 | .unwrap();
110 |
111 | let filter_item_keyword_wrapper_as_el = filter_item_keyword_wrapper
112 | .dyn_into::()
113 | .unwrap();
114 |
115 | let filter_item_keyword = filter_item_keyword_wrapper_as_el
116 | .query_selector(".filter-item-keyword")
117 | .unwrap();
118 |
119 | let filter_item_keyword_as_el: Element = filter_item_keyword
120 | .unwrap()
121 | .dyn_into()
122 | .unwrap();
123 |
124 | let text_of_filter_item_keyword = filter_item_keyword_as_el
125 | .text_content()
126 | .unwrap();
127 |
128 | let text_of_filter_item_keyword = text_of_filter_item_keyword
129 | .trim()
130 | .to_owned();
131 |
132 | let mut filter_summary_text_to_filter_target =
133 | obtain_filter_summary_text_to_filter_target_text_from_local_storage();
134 |
135 | filter_summary_text_to_filter_target.remove(&text_of_filter_item_keyword);
136 |
137 | let filter_summary_text_to_filter_target_as_stringified_json =
138 | stringify_filter_summary_text_to_filter_target_text_from_map(
139 | &filter_summary_text_to_filter_target,
140 | );
141 |
142 | write_sidebar_items_as_stringified_json_to_local_storage(
143 | &filter_summary_text_to_filter_target_as_stringified_json,
144 | );
145 | },
146 |
147 | | "filter-selector-wrapper" =>
148 | {
149 | let filter_item_wrapper_as_node = ic_remove_or_filter_selector_wrapper
150 | .parent_node()
151 | .unwrap();
152 |
153 | let filter_item_keyword_wrapper = filter_item_wrapper_as_node
154 | .first_child()
155 | .unwrap();
156 |
157 | let filter_item_keyword_wrapper_as_el = filter_item_keyword_wrapper
158 | .dyn_into::()
159 | .unwrap();
160 |
161 | let filter_item_keyword = filter_item_keyword_wrapper_as_el
162 | .query_selector(".filter-item-keyword")
163 | .unwrap();
164 |
165 | let filter_item_keyword_as_el: Element = filter_item_keyword
166 | .unwrap()
167 | .dyn_into()
168 | .unwrap();
169 |
170 | let text_of_filter_item_keyword = filter_item_keyword_as_el
171 | .text_content()
172 | .unwrap();
173 |
174 | let text_of_filter_item_keyword = text_of_filter_item_keyword
175 | .trim()
176 | .to_owned();
177 |
178 | let filter_item_wrapper: Element = filter_item_wrapper_as_node
179 | .clone()
180 | .dyn_into()
181 | .unwrap();
182 |
183 | let checkbox_container_div_children = filter_item_wrapper
184 | .query_selector_all("input[type='checkbox']")
185 | .unwrap();
186 |
187 | let checkbox_container_div_children_length =
188 | checkbox_container_div_children.length();
189 |
190 | let checkbox_container_div_children_as_vec_of_els: Vec = (1
191 | ..checkbox_container_div_children_length)
192 | .map(|index| {
193 | checkbox_container_div_children
194 | .item(index)
195 | .unwrap()
196 | })
197 | .map(|item| {
198 | item.dyn_into::()
199 | .unwrap()
200 | })
201 | .collect();
202 |
203 | let checkbox_container_div_children_as_vec_of_els_length =
204 | checkbox_container_div_children_as_vec_of_els.len();
205 |
206 | let checkbox_id_to_checkbox_toggle_state = (0
207 | ..checkbox_container_div_children_as_vec_of_els_length)
208 | .map(|index| {
209 | let checkbox_id = checkbox_container_div_children_as_vec_of_els
210 | .get(index)
211 | .unwrap()
212 | .get_attribute("id")
213 | .unwrap();
214 |
215 | let checkbox_toggle_state =
216 | checkbox_container_div_children_as_vec_of_els
217 | .get(index)
218 | .unwrap()
219 | .clone()
220 | .dyn_into::()
221 | .unwrap()
222 | .checked();
223 |
224 | (checkbox_id, checkbox_toggle_state)
225 | })
226 | .collect::>();
227 |
228 | let checkbox_id_to_checkbox_toggle_state_as_stringified_json =
229 | serde_json::to_string(&checkbox_id_to_checkbox_toggle_state).unwrap();
230 |
231 | let some_checkboxes_are_true = checkbox_id_to_checkbox_toggle_state
232 | .values()
233 | .any(|checkbox_toggle_state| *checkbox_toggle_state);
234 |
235 | let vector_of_all_checkbox_ids_that_are_true =
236 | checkbox_id_to_checkbox_toggle_state
237 | .iter()
238 | .filter(|(_checkbox_id, checkbox_toggle_state)| **checkbox_toggle_state)
239 | .map(|(checkbox_id, _checkbox_toggle_state)| checkbox_id)
240 | .collect::>();
241 |
242 | let vector_of_all_checkbox_ids_that_are_true =
243 | vector_of_all_checkbox_ids_that_are_true
244 | .iter()
245 | .map(|s| {
246 | let mut s = s.clone();
247 | let mut s = s
248 | .split("-")
249 | .collect::>();
250 |
251 | let mut s = s
252 | .iter_mut()
253 | .map(|s| {
254 | let mut s = s
255 | .chars()
256 | .collect::>();
257 | s[0] = s[0].to_ascii_uppercase();
258 | s.iter()
259 | .collect::()
260 | })
261 | .collect::>();
262 |
263 | let kek = s
264 | .get(1)
265 | .unwrap()
266 | .to_string();
267 | kek
268 |
269 | })
270 | .collect::>();
271 |
272 | let vector_of_all_checkbox_ids_that_are_true_as_joined_string =
273 | vector_of_all_checkbox_ids_that_are_true
274 | .iter()
275 | .map(|s| s.to_string())
276 | .collect::>()
277 | .join(",");
278 |
279 | let mut filter_summary_text_to_filter_target_text_ =
280 | obtain_filter_summary_text_to_filter_target_text_from_local_storage();
281 |
282 | filter_summary_text_to_filter_target_text_.insert(
283 | text_of_filter_item_keyword,
284 | vector_of_all_checkbox_ids_that_are_true_as_joined_string,
285 | );
286 |
287 | let filter_summary_text_to_filter_target_text_as_stringified_json =
288 | stringify_filter_summary_text_to_filter_target_text_from_map(
289 | &filter_summary_text_to_filter_target_text_,
290 | );
291 |
292 | write_sidebar_items_as_stringified_json_to_local_storage(
293 | &filter_summary_text_to_filter_target_text_as_stringified_json,
294 | );
295 |
296 | event.stop_propagation();
297 | },
298 |
299 | | _ =>
300 | {
301 | let mut parent = ic_remove_or_filter_selector_wrapper.parent_element();
302 |
303 | let mut found = false;
304 |
305 | let mut parent_clone = parent.clone();
306 |
307 | while let Some(element) = parent
308 | {
309 | if let Some(class_string) = element.get_attribute("class")
310 | {
311 | let class_list: Vec<&str> = class_string
312 | .split_whitespace()
313 | .collect();
314 |
315 | if class_list.contains(&"filter-selector-wrapper")
316 | {
317 | found = true;
318 |
319 | event.stop_propagation();
320 |
321 | break;
322 | }
323 | }
324 |
325 | parent = element.parent_element();
326 |
327 | parent_clone = parent.clone()
328 | }
329 |
330 | if found
331 | {
332 | let filter_item_wrapper_as_node = parent_clone
333 | .expect("no parent found")
334 | .parent_node()
335 | .unwrap();
336 |
337 | let filter_item_wrapper: Element = filter_item_wrapper_as_node
338 | .clone()
339 | .dyn_into()
340 | .unwrap();
341 |
342 | let filter_item_keyword_wrapper = filter_item_wrapper
343 | .first_child()
344 | .unwrap();
345 |
346 | let filter_item_keyword_wrapper_as_el = filter_item_keyword_wrapper
347 | .dyn_into::()
348 | .unwrap();
349 |
350 | let filter_item_keyword = filter_item_keyword_wrapper_as_el
351 | .query_selector(".filter-item-keyword")
352 | .unwrap();
353 |
354 | let filter_item_keyword_as_el: Element = filter_item_keyword
355 | .unwrap()
356 | .dyn_into()
357 | .unwrap();
358 |
359 | let text_of_filter_item_keyword = filter_item_keyword_as_el
360 | .text_content()
361 | .unwrap();
362 |
363 | let text_of_filter_item_keyword = text_of_filter_item_keyword
364 | .trim()
365 | .to_owned();
366 |
367 | let checkbox_container_div_children = filter_item_wrapper
368 | .query_selector_all("input[type='checkbox']")
369 | .unwrap();
370 |
371 | let checkbox_container_div_children_length =
372 | checkbox_container_div_children.length();
373 |
374 | let checkbox_container_div_children_as_vec_of_els: Vec = (1
375 | ..checkbox_container_div_children_length)
376 | .map(|index| {
377 | checkbox_container_div_children
378 | .item(index)
379 | .unwrap()
380 | })
381 | .map(|item| {
382 | item.dyn_into::()
383 | .unwrap()
384 | })
385 | .collect();
386 |
387 | let checkbox_container_div_children_as_vec_of_els_length =
388 | checkbox_container_div_children_as_vec_of_els.len();
389 |
390 | let checkbox_id_to_checkbox_toggle_state = (0
391 | ..checkbox_container_div_children_as_vec_of_els_length)
392 | .map(|index| {
393 | let checkbox_id = checkbox_container_div_children_as_vec_of_els
394 | .get(index)
395 | .unwrap()
396 | .get_attribute("id")
397 | .unwrap();
398 |
399 | let checkbox_toggle_state =
400 | checkbox_container_div_children_as_vec_of_els
401 | .get(index)
402 | .unwrap()
403 | .clone()
404 | .dyn_into::()
405 | .unwrap()
406 | .checked();
407 |
408 | (checkbox_id, checkbox_toggle_state)
409 | })
410 | .collect::>();
411 |
412 | let checkbox_id_to_checkbox_toggle_state_as_stringified_json =
413 | serde_json::to_string(&checkbox_id_to_checkbox_toggle_state).unwrap();
414 |
415 | let some_checkboxes_are_true = checkbox_id_to_checkbox_toggle_state
416 | .values()
417 | .any(|checkbox_toggle_state| *checkbox_toggle_state);
418 |
419 | let vector_of_all_checkbox_ids_that_are_true =
420 | checkbox_id_to_checkbox_toggle_state
421 | .iter()
422 | .filter(|(_checkbox_id, checkbox_toggle_state)| {
423 | **checkbox_toggle_state
424 | })
425 | .map(|(checkbox_id, _checkbox_toggle_state)| checkbox_id)
426 | .collect::>();
427 |
428 | let vector_of_all_checkbox_ids_that_are_true =
429 | vector_of_all_checkbox_ids_that_are_true
430 | .iter()
431 | .map(|s| {
432 | let mut s = s.clone();
433 | let mut s = s
434 | .split("-")
435 | .collect::>();
436 |
437 | let mut s = s
438 | .iter_mut()
439 | .map(|s| {
440 | let mut s = s
441 | .chars()
442 | .collect::>();
443 | s[0] = s[0].to_ascii_uppercase();
444 | s.iter()
445 | .collect::()
446 | })
447 | .collect::>();
448 |
449 | let kek = s
450 | .get(1)
451 | .unwrap()
452 | .to_string();
453 | kek
454 | })
455 | .collect::>();
456 |
457 | let vector_of_all_checkbox_ids_that_are_true_as_joined_string =
458 | vector_of_all_checkbox_ids_that_are_true
459 | .iter()
460 | .map(|s| s.to_string())
461 | .collect::>()
462 | .join(",");
463 |
464 | let mut filter_summary_text_to_filter_target_text_ =
465 | obtain_filter_summary_text_to_filter_target_text_from_local_storage();
466 |
467 | filter_summary_text_to_filter_target_text_.insert(
468 | text_of_filter_item_keyword,
469 | vector_of_all_checkbox_ids_that_are_true_as_joined_string,
470 | );
471 |
472 | let filter_summary_text_to_filter_target_text_as_stringified_json =
473 | stringify_filter_summary_text_to_filter_target_text_from_map(
474 | &filter_summary_text_to_filter_target_text_,
475 | );
476 |
477 | write_sidebar_items_as_stringified_json_to_local_storage(
478 | &filter_summary_text_to_filter_target_text_as_stringified_json,
479 | );
480 | }
481 | },
482 | }
483 | }
484 |
485 | match obtain_list_of_titleline_spans_as_rust_list_of_links_as_rust_list_of_hnusers_as_rust()
486 | {
487 | | Ok(
488 | (
489 | list_of_titleline_spans_as_rust_,
490 | list_of_links_as_rust_,
491 | list_of_comments_as_rust_,
492 | list_of_hnusers_as_rust_,
493 | )
494 | ) =>
495 | {
496 | for titleline_span in &list_of_titleline_spans_as_rust_
497 | {
498 | select_submission_elements_and_set_their_style(
499 | &titleline_span,
500 | "titleline_span",
501 | "",
502 | );
503 | }
504 |
505 | for link in &list_of_links_as_rust_
506 | {
507 | select_submission_elements_and_set_their_style(&link, "link", "");
508 | }
509 |
510 | for comment in &list_of_comments_as_rust_
511 | {
512 | select_submission_elements_and_set_their_style(&comment, "comment", "");
513 | }
514 |
515 | for username in &list_of_hnusers_as_rust_
516 | {
517 | select_submission_elements_and_set_their_style(&username, "hnuser", "");
518 | }
519 | },
520 | | Err(err) =>
521 | {
522 | console::error_1(&format!("An error occurred: {:?}", err).into());
523 | },
524 | }
525 |
526 | let window = web_sys::window().expect("should have a Window");
527 |
528 | let closure = Closure::once(move || {
529 | remove_all_children_of_filter_items_container();
530 | load_items_from_locastorage_populate_sidebar_and_apply_filters();
531 | });
532 |
533 | window
534 | .request_animation_frame(
535 | closure
536 | .as_ref()
537 | .unchecked_ref(),
538 | )
539 | .expect("should register `requestAnimationFrame` OK");
540 |
541 | closure.forget();
542 | });
543 |
544 | listener.forget();
545 |
546 | Ok(())
547 | }
548 |
549 | use std::collections::HashSet;
550 |
551 | #[wasm_bindgen]
552 | pub fn register_filter_out_submissions_event_listener() -> Result<(), JsValue>
553 | {
554 | let document = obtain_document();
555 |
556 | let filter_button = &document
557 | .get_element_by_id("filter-button")
558 | .unwrap();
559 |
560 | let filter_button: Element = filter_button
561 | .clone()
562 | .dyn_into()
563 | .unwrap();
564 |
565 | let result =
566 | obtain_list_of_titleline_spans_as_rust_list_of_links_as_rust_list_of_hnusers_as_rust();
567 |
568 | let (
569 | list_of_titleline_spans_as_rust,
570 | list_of_links_as_rust,
571 | list_of_comments_as_rust,
572 | list_of_hnusers_as_rust,
573 | ) =
574 | match result
575 | {
576 | | Ok(value) => value,
577 | | Err(err) => return Err(err),
578 | };
579 |
580 | let document_ref = document;
581 |
582 | let listener = EventListener::new(&filter_button, "click", move |_event: &Event| {
583 | let document = document_ref.clone();
584 |
585 | let input = document
586 | .get_element_by_id("sidebar-filter-input")
587 | .unwrap();
588 |
589 | let input: Element = input
590 | .dyn_into()
591 | .unwrap();
592 |
593 | let input_value = input
594 | .dyn_into::()
595 | .unwrap()
596 | .value();
597 |
598 | let input_value_as_js = JsValue::from(&input_value);
599 |
600 | let object_str: String = input_value_as_js
601 | .as_string()
602 | .unwrap();
603 |
604 | let object_str_as_regex = Regex::new(&object_str);
605 |
606 | let object_str_as_regex = match object_str_as_regex
607 | {
608 | | Ok(regex) => regex,
609 | | Err(_) =>
610 | {
611 | Regex::new("invalid_regex").unwrap()
612 | },
613 | };
614 |
615 | let sidebar_items_container = &document
616 | .get_element_by_id("filter-items-container")
617 | .unwrap();
618 |
619 | let sidebar_items_container: Element = sidebar_items_container
620 | .clone()
621 | .dyn_into()
622 | .unwrap();
623 |
624 | let checkbox_container_div = document
625 | .get_element_by_id("checkbox-container")
626 | .unwrap();
627 |
628 | let checkbox_container_div: Element = checkbox_container_div
629 | .dyn_into()
630 | .unwrap();
631 |
632 | let checkbox_container_div_children = checkbox_container_div
633 | .query_selector_all("input[type='checkbox']")
634 | .unwrap();
635 |
636 | let checkbox_container_div_children_length = checkbox_container_div_children.length();
637 |
638 | let checkbox_container_div_children_as_vec_of_els: Vec = (0
639 | ..checkbox_container_div_children_length)
640 | .map(|index| {
641 | checkbox_container_div_children
642 | .item(index)
643 | .unwrap()
644 | })
645 | .map(|item| {
646 | item.dyn_into::()
647 | .unwrap()
648 | })
649 | .collect();
650 |
651 | let checkbox_container_div_children_as_vec_of_els_as_string =
652 | checkbox_container_div_children_as_vec_of_els
653 | .iter()
654 | .map(|el| el.outer_html())
655 | .collect::>()
656 | .join("\n");
657 |
658 | let checkbox_container_div_children_as_vec_of_els_length =
659 | checkbox_container_div_children_as_vec_of_els.len();
660 |
661 | let checkbox_id_to_checkbox_toggle_state = (0
662 | ..checkbox_container_div_children_as_vec_of_els_length)
663 | .map(|index| {
664 | let checkbox_id = checkbox_container_div_children_as_vec_of_els
665 | .get(index)
666 | .unwrap()
667 | .get_attribute("id")
668 | .unwrap();
669 |
670 | let checkbox_toggle_state = checkbox_container_div_children_as_vec_of_els
671 | .get(index)
672 | .unwrap()
673 | .clone()
674 | .dyn_into::()
675 | .unwrap()
676 | .checked();
677 |
678 | (checkbox_id, checkbox_toggle_state)
679 | })
680 | .collect::>();
681 |
682 | let checkbox_id_to_checkbox_toggle_state_as_stringified_json =
683 | serde_json::to_string(&checkbox_id_to_checkbox_toggle_state).unwrap();
684 |
685 | let vector_of_all_checkbox_ids_that_are_true = checkbox_id_to_checkbox_toggle_state
686 | .iter()
687 | .filter(|(_checkbox_id, checkbox_toggle_state)| **checkbox_toggle_state)
688 | .map(|(checkbox_id, _checkbox_toggle_state)| checkbox_id)
689 | .collect::>();
690 |
691 | let vector_of_all_checkbox_ids_that_are_true = vector_of_all_checkbox_ids_that_are_true
692 | .iter()
693 | .map(|s| {
694 | let mut s = s.clone();
695 | let mut s = s
696 | .split("-")
697 | .collect::>();
698 |
699 | let mut s = s
700 | .iter_mut()
701 | .map(|s| {
702 | let mut s = s
703 | .chars()
704 | .collect::>();
705 | s[0] = s[0].to_ascii_uppercase();
706 | s.iter()
707 | .collect::()
708 | })
709 | .collect::>();
710 |
711 | let kek = s
712 | .get(0)
713 | .unwrap()
714 | .to_string();
715 |
716 | kek
717 | })
718 | .collect::>();
719 |
720 | let vector_of_all_checkbox_ids_that_are_true_as_joined_string =
721 | vector_of_all_checkbox_ids_that_are_true
722 | .iter()
723 | .map(|s| s.to_string())
724 | .collect::>()
725 | .join(",");
726 |
727 | let mut object_str_to_checkbox_id = IndexMap::new();
728 |
729 | object_str_to_checkbox_id.insert(&object_str, vector_of_all_checkbox_ids_that_are_true.clone());
730 |
731 | let filter_summary_texts = object_str_to_checkbox_id
732 | .keys()
733 | .collect::>();
734 |
735 | let filter_target_texts = object_str_to_checkbox_id
736 | .values()
737 | .collect::>();
738 |
739 | let object_str_to_checkbox_id_as_vec_of_tuples = filter_summary_texts
740 | .iter()
741 | .zip(filter_target_texts.iter())
742 | .collect::>();
743 |
744 | let object_str_to_checkbox_id_as_json = json!(
745 | {
746 | "sidebar_items": object_str_to_checkbox_id_as_vec_of_tuples
747 | }
748 | );
749 |
750 | let object_str_to_checkbox_id_as_stringified_json =
751 | object_str_to_checkbox_id_as_json.to_string();
752 |
753 | let some_checkboxes_are_true = checkbox_id_to_checkbox_toggle_state
754 | .values()
755 | .any(|checkbox_toggle_state| *checkbox_toggle_state);
756 |
757 | if some_checkboxes_are_true
758 | {
759 | let mut filter_summary_text_to_filter_target_text_from_local_storage =
760 | obtain_filter_summary_text_to_filter_target_text_from_local_storage();
761 |
762 | let object_str_key_is_already_present_in_filter_summary_text_to_filter_target_text_from_local_storage =
763 | filter_summary_text_to_filter_target_text_from_local_storage
764 | .contains_key(&object_str);
765 |
766 | if object_str_key_is_already_present_in_filter_summary_text_to_filter_target_text_from_local_storage
767 | {
768 | let string_of_targets =
769 | filter_summary_text_to_filter_target_text_from_local_storage
770 | .get(&object_str)
771 | .unwrap()
772 | .clone();
773 |
774 | let vector_of_targets = string_of_targets
775 | .split(",")
776 | .collect::>();
777 |
778 | let vector_of_all_checkbox_ids_that_are_true_: Vec<&str> = vector_of_all_checkbox_ids_that_are_true
779 | .iter()
780 | .map(|s| s.as_str())
781 | .collect();
782 |
783 | let concatenated_vec: Vec<&str> = vector_of_targets
784 | .iter()
785 | .chain(vector_of_all_checkbox_ids_that_are_true_.iter())
786 | .cloned()
787 | .collect();
788 |
789 | let hashset_of_targets = concatenated_vec
790 | .iter()
791 | .collect::>();
792 |
793 | let joined_string_of_targets = hashset_of_targets
794 | .iter()
795 | .map(|s| s.to_string())
796 | .collect::>()
797 | .join(",");
798 |
799 | filter_summary_text_to_filter_target_text_from_local_storage.insert(
800 | object_str,
801 | joined_string_of_targets,
802 | );
803 |
804 | }
805 | else
806 | {
807 |
808 | filter_summary_text_to_filter_target_text_from_local_storage.insert(
809 | object_str,
810 | vector_of_all_checkbox_ids_that_are_true_as_joined_string,
811 | );
812 | };
813 |
814 | let filter_summary_text_to_filter_target_text_from_local_storage_as_stringified_json =
815 | stringify_filter_summary_text_to_filter_target_text_from_map(
816 | &filter_summary_text_to_filter_target_text_from_local_storage,
817 | );
818 |
819 | write_sidebar_items_as_stringified_json_to_local_storage(
820 | &filter_summary_text_to_filter_target_text_from_local_storage_as_stringified_json,
821 | );
822 | }
823 |
824 | remove_all_children_of_filter_items_container();
825 |
826 | let input = document
827 | .get_element_by_id("sidebar-filter-input")
828 | .unwrap();
829 |
830 | let input: Element = input
831 | .dyn_into()
832 | .unwrap();
833 |
834 | let input_element = input.dyn_into::().unwrap();
835 |
836 | if some_checkboxes_are_true {
837 | input_element.set_value("");
838 | };
839 |
840 | _ = load_items_from_locastorage_populate_sidebar_and_apply_filters();
841 | });
842 |
843 | listener.forget();
844 |
845 | Ok(())
846 | }
847 |
848 | #[wasm_bindgen]
849 | pub fn restore_active_tab_from_previous_session_and_register_filter_tab_switching_event_listener() -> Result<(), JsValue>
850 | {
851 | let document = obtain_document();
852 |
853 | let list_of_tab_buttons = document
854 | .query_selector_all(".tab")
855 | .unwrap();
856 |
857 | let list_of_tab_buttons_as_rust: Vec = (0..list_of_tab_buttons.length())
858 | .map(|index| {
859 | list_of_tab_buttons
860 | .item(index)
861 | .ok_or_else(|| JsValue::from_str("Missing tab at index"))
862 | .and_then(|item| {
863 | item.dyn_into::()
864 | .map_err(|_| JsValue::from_str("Failed to cast to HtmlElement"))
865 | })
866 | })
867 | .collect::>()
868 | .unwrap();
869 |
870 | let list_of_tab_contents = document
871 | .query_selector_all(".tab-content")
872 | .unwrap();
873 |
874 | let list_of_tab_contents_as_rust: Vec = (0..list_of_tab_contents.length())
875 | .map(|index| {
876 | list_of_tab_contents
877 | .item(index)
878 | .ok_or_else(|| JsValue::from_str("Missing tab content at index"))
879 | .and_then(|item| {
880 | item.dyn_into::()
881 | .map_err(|_| JsValue::from_str("Failed to cast to HtmlElement"))
882 | })
883 | })
884 | .collect::>()
885 | .unwrap();
886 |
887 | let local_storage = web_sys::window()
888 | .unwrap()
889 | .local_storage()
890 | .unwrap()
891 | .unwrap();
892 |
893 | let name_of_active_tab = local_storage
894 | .get_item("name_of_active_tab")
895 | .unwrap()
896 | .unwrap_or_else(
897 | || {
898 | "settings-tab".to_owned()
899 | },
900 | );
901 |
902 | let list_of_tab_contents_as_rust_clone_1 = list_of_tab_contents_as_rust.clone();
903 |
904 | for tab_content in &list_of_tab_contents_as_rust_clone_1 {
905 |
906 | let tab_content_as_el = tab_content.clone();
907 |
908 | let tab_content_class_name = tab_content_as_el.class_name();
909 |
910 | if tab_content_class_name.contains(&name_of_active_tab) {
911 |
912 | tab_content_as_el.set_attribute("style", "");
913 |
914 | }
915 | else {
916 | tab_content_as_el.set_attribute("style", "display: none");
917 |
918 | }
919 | }
920 |
921 | for tab_button in &list_of_tab_buttons_as_rust {
922 |
923 | let tab_button_as_el = tab_button.clone();
924 |
925 | let current_class_name = &tab_button_as_el.class_name();
926 |
927 | if (
928 | current_class_name.contains(&name_of_active_tab)
929 | )
930 | {
931 | let class_name_with_active = format!("{} active", current_class_name);
932 |
933 | let class_name_with_active = class_name_with_active
934 | .split_whitespace()
935 | .collect::>()
936 | .join(" ");
937 |
938 | tab_button_as_el.set_class_name(&class_name_with_active);
939 | }
940 |
941 |
942 |
943 | let list_of_tab_buttons_as_rust_clone = list_of_tab_buttons_as_rust.clone();
944 | let list_of_tab_contents_as_rust_clone = list_of_tab_contents_as_rust.clone();
945 |
946 | let listener = EventListener::new(&tab_button, "click", move |event: &Event| {
947 |
948 | for tab_button in &list_of_tab_buttons_as_rust_clone {
949 |
950 | let tab_button_as_el = tab_button.clone();
951 |
952 | let current_class_name = &tab_button_as_el.class_name();
953 |
954 | let class_name_without_active = current_class_name
955 | .replace("active", "");
956 |
957 | tab_button_as_el.set_class_name(&class_name_without_active);
958 | }
959 |
960 | let active_tab_button = event
961 | .target()
962 | .unwrap();
963 |
964 | let active_tab_button_as_el = active_tab_button
965 | .dyn_into::()
966 | .unwrap();
967 |
968 | let current_active_class_name = &active_tab_button_as_el.class_name();
969 |
970 | let class_name_with_active = format!("{} active", current_active_class_name);
971 |
972 | let class_name_with_active = class_name_with_active
973 | .split_whitespace()
974 | .collect::>()
975 | .join(" ");
976 |
977 | active_tab_button_as_el.set_class_name(&class_name_with_active);
978 |
979 | let first_class = &class_name_with_active
980 | .split_whitespace()
981 | .collect::>()
982 | .get(0)
983 | .unwrap()
984 | .to_string();
985 |
986 | let local_storage = web_sys::window()
987 | .unwrap()
988 | .local_storage()
989 | .unwrap()
990 | .unwrap();
991 |
992 | local_storage
993 | .set_item("name_of_active_tab", &first_class)
994 | .unwrap();
995 |
996 | let name_of_first_class_of_active_tab_button = &class_name_with_active
997 | .split_whitespace()
998 | .collect::>()
999 | .get(0)
1000 | .unwrap().to_string();
1001 |
1002 | let name_of_first_class_of_active_tab_button_as_js = JsValue::from(name_of_first_class_of_active_tab_button.clone());
1003 |
1004 | for tab_content in &list_of_tab_contents_as_rust_clone {
1005 |
1006 | let tab_content_as_el = tab_content.clone();
1007 |
1008 | let tab_content_class_name = tab_content_as_el.class_name();
1009 |
1010 | if tab_content_class_name.contains(&name_of_first_class_of_active_tab_button.as_str()) {
1011 |
1012 | let tab_content_that_matches_tab_button_name = tab_content_as_el.clone();
1013 |
1014 | tab_content_as_el.set_attribute("style", "");
1015 | }
1016 | else {
1017 | tab_content_as_el.set_attribute("style", "display: none");
1018 |
1019 | }
1020 | }
1021 | });
1022 |
1023 | listener.forget();
1024 | }
1025 |
1026 | Ok(())
1027 | }
1028 |
1029 | #[wasm_bindgen]
1030 | pub fn load_settings_from_local_storage() -> Result<(), JsValue>
1031 | {
1032 |
1033 | let document = obtain_document();
1034 |
1035 | let substitute_placeholder_checkbox = document
1036 | .get_element_by_id("substitute-placeholder-checkbox")
1037 | .unwrap();
1038 |
1039 | let substitute_placeholder_checkbox_as_el: Element = substitute_placeholder_checkbox
1040 | .dyn_into()
1041 | .unwrap();
1042 |
1043 | let local_storage = web_sys::window()
1044 | .unwrap()
1045 | .local_storage()
1046 | .unwrap()
1047 | .unwrap();
1048 |
1049 | let substitute_placeholder_checkbox_state = local_storage
1050 | .get_item("substitute_placeholder")
1051 | .unwrap()
1052 | .unwrap_or_else(
1053 | || {
1054 | "false".to_owned()
1055 | },
1056 | );
1057 |
1058 | let substitute_placeholder_checkbox_state_as_bool = substitute_placeholder_checkbox_state
1059 | .parse::()
1060 | .unwrap();
1061 |
1062 | substitute_placeholder_checkbox_as_el
1063 | .dyn_into::()
1064 | .unwrap()
1065 | .set_checked(substitute_placeholder_checkbox_state_as_bool);
1066 |
1067 | let enable_filters_checkbox = document
1068 | .get_element_by_id("enable-filters-checkbox")
1069 | .unwrap();
1070 |
1071 | let enable_filters_checkbox_as_el: Element = enable_filters_checkbox
1072 | .dyn_into()
1073 | .unwrap();
1074 |
1075 | let local_storage = web_sys::window()
1076 | .unwrap()
1077 | .local_storage()
1078 | .unwrap()
1079 | .unwrap();
1080 |
1081 | let enable_filters_checkbox_state = local_storage
1082 | .get_item("enable_filters")
1083 | .unwrap()
1084 | .unwrap_or_else(
1085 | || {
1086 | "true".to_owned()
1087 | },
1088 | );
1089 |
1090 | let enable_filters_checkbox_state_as_bool = enable_filters_checkbox_state
1091 | .parse::()
1092 | .unwrap();
1093 |
1094 | enable_filters_checkbox_as_el
1095 | .dyn_into::()
1096 | .unwrap()
1097 | .set_checked(enable_filters_checkbox_state_as_bool);
1098 |
1099 | let hide_children_comments_checkbox = document
1100 | .get_element_by_id("hide-children-comments-checkbox")
1101 | .unwrap();
1102 |
1103 | let hide_children_comments_checkbox_as_el: Element = hide_children_comments_checkbox
1104 | .dyn_into()
1105 | .unwrap();
1106 |
1107 | let local_storage = web_sys::window()
1108 | .unwrap()
1109 | .local_storage()
1110 | .unwrap()
1111 | .unwrap();
1112 |
1113 | let hide_children_comments_checkbox_state = local_storage
1114 | .get_item("hide_children_comments")
1115 | .unwrap()
1116 | .unwrap_or_else(
1117 | || {
1118 | "true".to_owned()
1119 | },
1120 | );
1121 |
1122 | let hide_children_comments_checkbox_state_as_bool = hide_children_comments_checkbox_state
1123 | .parse::()
1124 | .unwrap();
1125 |
1126 | hide_children_comments_checkbox_as_el
1127 | .dyn_into::()
1128 | .unwrap()
1129 | .set_checked(hide_children_comments_checkbox_state_as_bool);
1130 |
1131 | Ok(())
1132 | }
1133 |
1134 | #[wasm_bindgen]
1135 | pub fn register_settings_checkboxes_event_listener() -> Result<(), JsValue>
1136 | {
1137 | let document = obtain_document();
1138 |
1139 | let substitute_placeholder_checkbox = document
1140 | .get_element_by_id("substitute-placeholder-checkbox")
1141 | .unwrap();
1142 |
1143 | let substitute_placeholder_checkbox_as_el: Element = substitute_placeholder_checkbox
1144 | .dyn_into()
1145 | .unwrap();
1146 |
1147 | let substitute_placeholder_checkbox_listener = EventListener::new(&substitute_placeholder_checkbox_as_el, "click", move |event: &Event| {
1148 |
1149 | let substitute_placeholder_checkbox_as_el = event
1150 | .target()
1151 | .unwrap();
1152 |
1153 | let substitute_placeholder_checkbox_as_el = substitute_placeholder_checkbox_as_el
1154 | .dyn_into::()
1155 | .unwrap();
1156 |
1157 | let substitute_placeholder_checkbox_state = substitute_placeholder_checkbox_as_el
1158 | .checked();
1159 |
1160 | let substitute_placeholder_checkbox_state_as_string = substitute_placeholder_checkbox_state
1161 | .to_string();
1162 |
1163 | let local_storage = window()
1164 | .unwrap()
1165 | .local_storage()
1166 | .unwrap()
1167 | .unwrap();
1168 |
1169 | local_storage
1170 | .set_item(
1171 | "substitute_placeholder",
1172 | &substitute_placeholder_checkbox_state_as_string
1173 | )
1174 | .unwrap();
1175 |
1176 | remove_all_children_of_filter_items_container();
1177 |
1178 | load_items_from_locastorage_populate_sidebar_and_apply_filters();
1179 | });
1180 |
1181 | substitute_placeholder_checkbox_listener.forget();
1182 |
1183 | let enable_filters_checkbox = document
1184 | .get_element_by_id("enable-filters-checkbox")
1185 | .unwrap();
1186 |
1187 | let enable_filters_checkbox_as_el: Element = enable_filters_checkbox
1188 | .dyn_into()
1189 | .unwrap();
1190 |
1191 | let enable_filters_checkbox_listener = EventListener::new(&enable_filters_checkbox_as_el, "click", move |event: &Event| {
1192 |
1193 | let enable_filters_checkbox_as_el = event
1194 | .target()
1195 | .unwrap();
1196 |
1197 | let enable_filters_checkbox_as_el = enable_filters_checkbox_as_el
1198 | .dyn_into::()
1199 | .unwrap();
1200 |
1201 | let enable_filters_checkbox_state = enable_filters_checkbox_as_el
1202 | .checked();
1203 |
1204 | let enable_filters_checkbox_state_as_string = enable_filters_checkbox_state
1205 | .to_string();
1206 |
1207 | let local_storage = window()
1208 | .unwrap()
1209 | .local_storage()
1210 | .unwrap()
1211 | .unwrap();
1212 |
1213 | local_storage
1214 | .set_item(
1215 | "enable_filters",
1216 | &enable_filters_checkbox_state_as_string
1217 | )
1218 | .unwrap();
1219 |
1220 | remove_all_children_of_filter_items_container();
1221 |
1222 | load_items_from_locastorage_populate_sidebar_and_apply_filters();
1223 | });
1224 |
1225 | enable_filters_checkbox_listener.forget();
1226 |
1227 | let hide_children_comments_checkbox = document
1228 | .get_element_by_id("hide-children-comments-checkbox")
1229 | .unwrap();
1230 |
1231 | let hide_children_comments_checkbox_as_el: Element = hide_children_comments_checkbox
1232 | .dyn_into()
1233 | .unwrap();
1234 |
1235 | let hide_children_comments_checkbox_listener = EventListener::new(&hide_children_comments_checkbox_as_el, "click", move |event: &Event| {
1236 |
1237 | let hide_children_comments_checkbox_as_el = event
1238 | .target()
1239 | .unwrap();
1240 |
1241 | let hide_children_comments_checkbox_as_el = hide_children_comments_checkbox_as_el
1242 | .dyn_into::()
1243 | .unwrap();
1244 |
1245 | let hide_children_comments_checkbox_state = hide_children_comments_checkbox_as_el
1246 | .checked();
1247 |
1248 | let hide_children_comments_checkbox_state_as_string = hide_children_comments_checkbox_state
1249 | .to_string();
1250 |
1251 | let local_storage = window()
1252 | .unwrap()
1253 | .local_storage()
1254 | .unwrap()
1255 | .unwrap();
1256 |
1257 | local_storage
1258 | .set_item(
1259 | "hide_children_comments",
1260 | &hide_children_comments_checkbox_state_as_string
1261 | )
1262 | .unwrap();
1263 |
1264 | remove_all_children_of_filter_items_container();
1265 |
1266 | load_items_from_locastorage_populate_sidebar_and_apply_filters();
1267 | });
1268 |
1269 | hide_children_comments_checkbox_listener.forget();
1270 |
1271 |
1272 |
1273 | Ok(())
1274 |
1275 | }
1276 |
1277 | #[wasm_bindgen]
1278 | pub fn add_donation_buttons_to_sidebar() -> Result<(), JsValue> {
1279 | let document = obtain_document();
1280 |
1281 | let settings_tab_content = document
1282 | .get_element_by_id("settings-checkbox-container")
1283 | .unwrap();
1284 |
1285 | let image_bytes_patreon = include_bytes!("../support-on-patreon.png");
1286 |
1287 | let base64_string_patreon = base64::encode(image_bytes_patreon);
1288 |
1289 | let data_url_patreon = format!("data:image/png;base64,{}", base64_string_patreon);
1290 |
1291 | let container_with_images = document
1292 | .create_element("div")
1293 | .unwrap();
1294 |
1295 | let container_with_images_as_el: Element = container_with_images
1296 | .dyn_into()
1297 | .unwrap();
1298 |
1299 | container_with_images_as_el.set_inner_html(
1300 | r#"
1301 | Support my work:
1302 |
1313 | "#
1314 | );
1315 |
1316 | settings_tab_content
1317 | .append_child(&container_with_images_as_el);
1318 |
1319 | let img_patreon = document
1320 | .get_element_by_id("patreon")
1321 | .unwrap()
1322 | .dyn_into::()
1323 | .expect("should be able to cast as img");
1324 |
1325 | img_patreon.set_src(&data_url_patreon);
1326 |
1327 | let image_bytes_liberapay = include_bytes!("../support-on-liberapay.png");
1328 |
1329 | let base64_string_liberapay = base64::encode(image_bytes_liberapay);
1330 |
1331 | let data_url_liberapay = format!("data:image/png;base64,{}", base64_string_liberapay);
1332 |
1333 | let img_liberapay = document
1334 | .get_element_by_id("liberapay")
1335 | .unwrap()
1336 | .dyn_into::()
1337 | .expect("should be able to cast as img");
1338 |
1339 | img_liberapay.set_src(&data_url_liberapay);
1340 |
1341 | Ok(())
1342 | }
1343 |
1344 | fn find_child_with_class(parent: &Element, class_name: &str) -> Result