inital no-js frontend
This commit is contained in:
parent
38f04320f0
commit
253de6ff13
17 changed files with 13 additions and 488 deletions
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
* This functions gets the saved cookies if it is present on the user's machine If it
|
||||
* is available then it is parsed and converted to an object which is then used to
|
||||
* retrieve the preferences that the user had selected previously and is then loaded
|
||||
* and used for displaying the user provided settings by setting them as the selected
|
||||
* options in the settings page.
|
||||
*
|
||||
* @function
|
||||
* @param {string} cookie - It takes the client settings cookie as a string.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setClientSettingsOnPage(cookie) {
|
||||
// Loop through all select tags and add their values to the cookie dictionary
|
||||
let engines = document.querySelectorAll('.engine')
|
||||
|
||||
document.querySelector('.select_all').checked = true
|
||||
|
||||
engines.forEach((engine) => {
|
||||
engine.checked = cookie[engine.parentNode.parentNode.innerText.trim()];
|
||||
if (!engine.checked) {
|
||||
document.querySelector('.select_all').checked = false
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is executed when any page on the website finishes loading and
|
||||
* this function retrieves the cookies if it is present on the user's machine.
|
||||
* If it is available then the saved cookies is display in the cookies tab
|
||||
* otherwise an appropriate message is displayed if it is not available.
|
||||
*
|
||||
* @function
|
||||
* @listens DOMContentLoaded
|
||||
* @returns {void}
|
||||
*/
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
try {
|
||||
// Decode the cookie value
|
||||
let cookie = decodeURIComponent(document.cookie)
|
||||
// Set the value of the input field to the decoded cookie value if it is not empty
|
||||
// Otherwise, display a message indicating that no cookies have been saved on the user's system
|
||||
if (cookie.length) {
|
||||
document.querySelector('.cookies input').value = cookie
|
||||
// This function displays the user provided settings on the settings page.
|
||||
setClientSettingsOnPage(JSON.parse(cookie.replace("appCookie=", "")))
|
||||
} else {
|
||||
document.querySelector('.cookies input').value =
|
||||
'No cookies have been saved on your system'
|
||||
}
|
||||
} catch (error) {
|
||||
// If there is an error decoding the cookie, log the error to the console
|
||||
// and display an error message in the input field
|
||||
console.error('Error decoding cookie:', error)
|
||||
document.querySelector('.cookies input').value = 'Error decoding cookie'
|
||||
}
|
||||
},
|
||||
false,
|
||||
)
|
|
@ -1,7 +0,0 @@
|
|||
/**
|
||||
* This function provides the ability for the button to toggle the dropdown error-box
|
||||
* in the search page.
|
||||
*/
|
||||
function toggleErrorBox() {
|
||||
document.querySelector('.dropdown_error_box').classList.toggle('show')
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/**
|
||||
* Selects the input element for the search box
|
||||
* @type {HTMLInputElement}
|
||||
*/
|
||||
const searchBox = document.querySelector('input')
|
||||
|
||||
/**
|
||||
* Redirects the user to the search results page with the query parameter
|
||||
*/
|
||||
function searchWeb() {
|
||||
const query = searchBox.value.trim()
|
||||
try {
|
||||
let safeSearchLevel = document.querySelector('.search_options select').value
|
||||
if (query) {
|
||||
window.location.href = `search?q=${encodeURIComponent(
|
||||
query,
|
||||
)}&safesearch=${encodeURIComponent(safeSearchLevel)}`
|
||||
}
|
||||
} catch (error) {
|
||||
if (query) {
|
||||
window.location.href = `search?q=${encodeURIComponent(query)}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for the 'Enter' key press event on the search box and calls the searchWeb function
|
||||
* @param {KeyboardEvent} e - The keyboard event object
|
||||
*/
|
||||
searchBox.addEventListener('keyup', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
searchWeb()
|
||||
}
|
||||
})
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
* Navigates to the next page by incrementing the current page number in the URL query string.
|
||||
* @returns {void}
|
||||
*/
|
||||
function navigate_forward() {
|
||||
let url = new URL(window.location);
|
||||
let searchParams = url.searchParams;
|
||||
|
||||
let q = searchParams.get('q');
|
||||
let page = parseInt(searchParams.get('page'));
|
||||
|
||||
if (isNaN(page)) {
|
||||
page = 1;
|
||||
} else {
|
||||
page++;
|
||||
}
|
||||
|
||||
window.location.href = `${url.origin}${url.pathname}?q=${encodeURIComponent(q)}&page=${page}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to the previous page by decrementing the current page number in the URL query string.
|
||||
* @returns {void}
|
||||
*/
|
||||
function navigate_backward() {
|
||||
let url = new URL(window.location);
|
||||
let searchParams = url.searchParams;
|
||||
|
||||
let q = searchParams.get('q');
|
||||
let page = parseInt(searchParams.get('page'));
|
||||
|
||||
if (isNaN(page)) {
|
||||
page = 0;
|
||||
} else if (page > 0) {
|
||||
page--;
|
||||
}
|
||||
|
||||
window.location.href = `${url.origin}${url.pathname}?q=${encodeURIComponent(q)}&page=${page}`;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
let url = new URL(window.location)
|
||||
let searchParams = url.searchParams
|
||||
|
||||
let safeSearchLevel = searchParams.get('safesearch')
|
||||
|
||||
if (
|
||||
safeSearchLevel >= 0 &&
|
||||
safeSearchLevel <= 2 &&
|
||||
safeSearchLevel !== null
|
||||
) {
|
||||
document.querySelector('.search_options select').value = safeSearchLevel
|
||||
}
|
||||
},
|
||||
false,
|
||||
)
|
|
@ -1,66 +0,0 @@
|
|||
/**
|
||||
* This function handles the toggling of selections of all upstream search engines
|
||||
* options in the settings page under the tab engines.
|
||||
*/
|
||||
function toggleAllSelection() {
|
||||
document
|
||||
.querySelectorAll('.engine')
|
||||
.forEach(
|
||||
(engine_checkbox) =>
|
||||
(engine_checkbox.checked =
|
||||
document.querySelector('.select_all').checked),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This function adds the functionality to sidebar buttons to only show settings
|
||||
* related to that tab.
|
||||
* @param {HTMLElement} current_tab - The current tab that was clicked.
|
||||
*/
|
||||
function setActiveTab(current_tab) {
|
||||
// Remove the active class from all tabs and buttons
|
||||
document
|
||||
.querySelectorAll('.tab')
|
||||
.forEach((tab) => tab.classList.remove('active'))
|
||||
document
|
||||
.querySelectorAll('.btn')
|
||||
.forEach((tab) => tab.classList.remove('active'))
|
||||
|
||||
// Add the active class to the current tab and its corresponding settings
|
||||
current_tab.classList.add('active')
|
||||
document
|
||||
.querySelector(`.${current_tab.innerText.toLowerCase().replace(' ', '_')}`)
|
||||
.classList.add('active')
|
||||
}
|
||||
|
||||
/**
|
||||
* This function adds the functionality to save all the user selected preferences
|
||||
* to be saved in a cookie on the users machine.
|
||||
*/
|
||||
function setClientSettings() {
|
||||
// Create an object to store the user's preferences
|
||||
let cookie_dictionary = new Object()
|
||||
|
||||
document.querySelectorAll('.engine').forEach((engine_checkbox) => {
|
||||
cookie_dictionary[engine_checkbox.parentNode.parentNode.innerText.trim()] = engine_checkbox.checked
|
||||
})
|
||||
|
||||
// Set the expiration date for the cookie to 1 year from the current date
|
||||
let expiration_date = new Date()
|
||||
expiration_date.setFullYear(expiration_date.getFullYear() + 1)
|
||||
|
||||
// Save the cookie to the user's machine
|
||||
document.cookie = `appCookie=${JSON.stringify(
|
||||
cookie_dictionary,
|
||||
)}; expires=${expiration_date.toUTCString()}`
|
||||
|
||||
// Display a success message to the user
|
||||
document.querySelector('.message').innerText =
|
||||
'✅ The settings have been saved sucessfully!!'
|
||||
|
||||
// Clear the success message after 10 seconds
|
||||
setTimeout(() => {
|
||||
document.querySelector('.message').innerText = ''
|
||||
}, 10000)
|
||||
}
|
||||
|
|
@ -86,7 +86,6 @@ async fn main() {
|
|||
.service(router::index) // index page
|
||||
.service(server::routes::search::search) // search page
|
||||
.service(router::about) // about page
|
||||
.service(router::settings) // settings page
|
||||
.default_service(web::route().to(router::not_found)) // error page
|
||||
})
|
||||
// Start server on 127.0.0.1 with the user provided port number. for example 127.0.0.1:8080.
|
||||
|
|
|
@ -2,11 +2,8 @@
|
|||
//! meta search engine website and provide appropriate response to each route/page
|
||||
//! when requested.
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
handler::{file_path, FileType},
|
||||
};
|
||||
use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
|
||||
use crate::handler::{file_path, FileType};
|
||||
use actix_web::{get, http::header::ContentType, HttpRequest, HttpResponse};
|
||||
use tokio::fs::read_to_string;
|
||||
|
||||
/// Handles the route of index page or main page of the `crabbysearch` meta search engine website.
|
||||
|
@ -42,21 +39,3 @@ pub async fn about() -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
|||
.content_type(ContentType::html())
|
||||
.body(crate::templates::views::about::about().0))
|
||||
}
|
||||
|
||||
/// Handles the route of settings page of the `crabbysearch` meta search engine website.
|
||||
#[get("/settings")]
|
||||
pub async fn settings(
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
|
||||
crate::templates::views::settings::settings(
|
||||
&config
|
||||
.upstream_search_engines
|
||||
.list()
|
||||
.iter()
|
||||
.map(|n| (*n, true))
|
||||
.collect(),
|
||||
)?
|
||||
.0,
|
||||
))
|
||||
}
|
||||
|
|
|
@ -14,10 +14,15 @@ use maud::{html, Markup, PreEscaped};
|
|||
/// It returns the compiled html code for the search bar as a result.
|
||||
pub fn bar(query: &str) -> Markup {
|
||||
html!(
|
||||
(PreEscaped("<div class=\"search_bar\">"))
|
||||
input type="search" name="search-box" value=(query) placeholder="Type to search";
|
||||
button type="submit" onclick="searchWeb()" {
|
||||
img src="./images/magnifying_glass.svg" alt="Info icon for error box";
|
||||
.search_container {
|
||||
(PreEscaped("<div class=\"search_bar\">"))
|
||||
form action="/search" method="get" {
|
||||
input type="search" name="query" value=(query) placeholder="Type to search";
|
||||
input type="hidden" name="page" value="0";
|
||||
button type="submit" {
|
||||
img src="./images/magnifying_glass.svg" alt="Info icon for error box";
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,5 +4,3 @@ pub mod bar;
|
|||
pub mod footer;
|
||||
pub mod header;
|
||||
pub mod navbar;
|
||||
pub mod search_bar;
|
||||
pub mod settings_tabs;
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
//! A module that handles `search bar` partial for the search page in the `crabbysearch` frontend.
|
||||
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
|
||||
use crate::{models::aggregation_models::EngineErrorInfo, templates::partials::bar::bar};
|
||||
|
||||
/// A constant holding the named safe search level options for the corresponding values 0, 1 and 2.
|
||||
const SAFE_SEARCH_LEVELS_NAME: [&str; 3] = ["None", "Low", "Moderate"];
|
||||
|
||||
/// A functions that handles the html code for the search bar for the search page.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `engine_errors_info` - It takes the engine errors list containing errors for each upstream
|
||||
/// search engine which failed to provide results as an argument.
|
||||
/// * `safe_search_level` - It takes the safe search level with values from 0-2 as an argument.
|
||||
/// * `query` - It takes the current search query provided by user as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html code for the search bar as a result.
|
||||
pub fn search_bar(
|
||||
engine_errors_info: &[EngineErrorInfo],
|
||||
safe_search_level: u8,
|
||||
query: &str,
|
||||
) -> Markup {
|
||||
html!(
|
||||
.search_area{
|
||||
(bar(query))
|
||||
.error_box {
|
||||
@if !engine_errors_info.is_empty(){
|
||||
button onclick="toggleErrorBox()" class="error_box_toggle_button"{
|
||||
img src="./images/warning.svg" alt="Info icon for error box";
|
||||
}
|
||||
.dropdown_error_box{
|
||||
@for errors in engine_errors_info{
|
||||
.error_item{
|
||||
span class="engine_name"{(errors.engine)}
|
||||
span class="engine_name"{(errors.error)}
|
||||
span class="severity_color" style="background: {{{this.severity_color}}};"{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@else {
|
||||
button onclick="toggleErrorBox()" class="error_box_toggle_button"{
|
||||
img src="./images/info.svg" alt="Warning icon for error box";
|
||||
}
|
||||
.dropdown_error_box {
|
||||
.no_errors{
|
||||
"Everything looks good 🙂!!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(PreEscaped("</div>"))
|
||||
.search_options {
|
||||
@if safe_search_level >= 3 {
|
||||
(PreEscaped("<select name=\"safe_search_levels\" disabled>"))
|
||||
}
|
||||
@else{
|
||||
(PreEscaped("<select name=\"safe_search_levels\">"))
|
||||
}
|
||||
@for (idx, name) in SAFE_SEARCH_LEVELS_NAME.iter().enumerate() {
|
||||
@if (safe_search_level as usize) == idx {
|
||||
option value=(idx) selected {(format!("SafeSearch: {name}"))}
|
||||
}
|
||||
@else{
|
||||
option value=(idx) {(format!("SafeSearch: {name}"))}
|
||||
}
|
||||
}
|
||||
(PreEscaped("</select>"))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
//! A module that handles the engines tab for setting page view in the `crabbysearch` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
/// A functions that handles the html code for the cookies tab for the settings page for the search page.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code for the cookies tab.
|
||||
pub fn cookies() -> Markup {
|
||||
html!(
|
||||
div class="cookies tab"{
|
||||
h1{"Cookies"}
|
||||
p class="description"{
|
||||
"This is the cookies are saved on your system and it contains the preferences
|
||||
you chose in the settings page"
|
||||
}
|
||||
input type="text" name="cookie_field" value="" readonly;
|
||||
p class="description"{
|
||||
"The cookies stored are not used by us for any malicious intend or for
|
||||
tracking you in any way."
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
//! A module that handles the engines tab for setting page view in the `crabbysearch` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
/// A functions that handles the html code for the engines tab for the settings page for the search page.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `engine_names` - It takes the key value pair list of all available engine names and there corresponding
|
||||
/// selected (enabled/disabled) value as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code for the engines tab.
|
||||
pub fn engines(engine_names: &Vec<(&str, bool)>) -> Markup {
|
||||
html!(
|
||||
div class="engines tab"{
|
||||
h1{"Engines"}
|
||||
h3{"select search engines"}
|
||||
p class="description"{
|
||||
"Select the search engines from the list of engines that you want results from"
|
||||
}
|
||||
.engine_selection{
|
||||
// Checks whether all the engines are selected or not if they are then the
|
||||
// checked `select_all` button is rendered otherwise the unchecked version
|
||||
// is rendered.
|
||||
@if engine_names.iter().all(|selected| selected.1){
|
||||
.toggle_btn{
|
||||
label class="switch"{
|
||||
input type="checkbox" class="select_all" onchange="toggleAllSelection()" checked;
|
||||
span class="slider round"{}
|
||||
}
|
||||
"Select All"
|
||||
}
|
||||
}
|
||||
@else{
|
||||
.toggle_btn {
|
||||
label class="switch"{
|
||||
input type="checkbox" class="select_all" onchange="toggleAllSelection()";
|
||||
span class="slider round"{}
|
||||
}
|
||||
"Select All"
|
||||
}
|
||||
}
|
||||
hr;
|
||||
@for (engine_name, selected) in engine_names{
|
||||
// Checks whether the `engine_name` is selected or not if they are then the
|
||||
// checked `engine` button is rendered otherwise the unchecked version is
|
||||
// rendered.
|
||||
@if *selected {
|
||||
.toggle_btn{
|
||||
label class="switch"{
|
||||
input type="checkbox" class="engine" checked;
|
||||
span class="slider round"{}
|
||||
}
|
||||
(format!("{}{}",&engine_name[..1].to_uppercase(), &engine_name[1..]))
|
||||
}
|
||||
}
|
||||
@else {
|
||||
.toggle_btn {
|
||||
label class="switch"{
|
||||
input type="checkbox" class="engine";
|
||||
span class="slider round"{}
|
||||
}
|
||||
(format!("{}{}",&engine_name[..1], &engine_name[1..]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
//! This module provides other modules to handle the partials for the tabs for the settings page
|
||||
//! view in the `crabbysearch` frontend.
|
||||
|
||||
pub mod cookies;
|
||||
pub mod engines;
|
|
@ -5,4 +5,3 @@ pub mod about;
|
|||
pub mod index;
|
||||
pub mod not_found;
|
||||
pub mod search;
|
||||
pub mod settings;
|
||||
|
|
|
@ -4,7 +4,7 @@ use maud::{html, Markup, PreEscaped};
|
|||
|
||||
use crate::{
|
||||
models::aggregation_models::SearchResults,
|
||||
templates::partials::{footer::footer, header::header, search_bar::search_bar},
|
||||
templates::partials::{bar::bar, footer::footer, header::header},
|
||||
};
|
||||
|
||||
/// A function that handles the html code for the search page view in the search engine frontend.
|
||||
|
@ -23,7 +23,7 @@ pub fn search(query: &str, search_results: &SearchResults) -> Markup {
|
|||
html!(
|
||||
(header())
|
||||
main class="results"{
|
||||
(search_bar(&search_results.engine_errors_info, search_results.safe_search_level, query))
|
||||
(bar(query))
|
||||
.results_aggregated{
|
||||
@if !search_results.results.is_empty() {
|
||||
@for result in search_results.results.iter(){
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
//! A module that handles the view for the settings page in the `crabbysearch` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
use crate::templates::partials::{
|
||||
footer::footer,
|
||||
header::header,
|
||||
settings_tabs::{cookies::cookies, engines::engines},
|
||||
};
|
||||
|
||||
/// A function that handles the html code for the settings page view in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `safe_search_level` - It takes the safe search level as an argument.
|
||||
/// * `colorscheme` - It takes the colorscheme name as an argument.
|
||||
/// * `theme` - It takes the theme name as an argument.
|
||||
/// * `animation` - It takes the animation name as an argument.
|
||||
/// * `engine_names` - It takes a list of engine names as an argument.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// This function returns a compiled html markup code on success otherwise returns a standard error
|
||||
/// message.
|
||||
pub fn settings(
|
||||
engine_names: &Vec<(&'static str, bool)>,
|
||||
) -> Result<Markup, Box<dyn std::error::Error>> {
|
||||
Ok(html!(
|
||||
(header())
|
||||
main class="settings"{
|
||||
h1{"Settings"}
|
||||
hr;
|
||||
.settings_container{
|
||||
.sidebar{
|
||||
div class="btn active" onclick="setActiveTab(this)"{"general"}
|
||||
.btn onclick="setActiveTab(this)"{"user interface"}
|
||||
.btn onclick="setActiveTab(this)"{"engines"}
|
||||
.btn onclick="setActiveTab(this)"{"cookies"}
|
||||
}
|
||||
.main_container{
|
||||
(engines(&engine_names))
|
||||
(cookies())
|
||||
p class="message"{}
|
||||
button type="submit" onclick="setClientSettings()"{"Save"}
|
||||
}
|
||||
}
|
||||
}
|
||||
script src="static/settings.js"{}
|
||||
script src="static/cookies.js"{}
|
||||
(footer())
|
||||
))
|
||||
}
|
Loading…
Add table
Reference in a new issue