about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--web/atward/src/index.html49
-rw-r--r--web/atward/src/main.rs105
2 files changed, 139 insertions, 15 deletions
diff --git a/web/atward/src/index.html b/web/atward/src/index.html
index 286bc6e546ad..a62d168bda0e 100644
--- a/web/atward/src/index.html
+++ b/web/atward/src/index.html
@@ -6,7 +6,28 @@
 <link rel="icon" type="image/webp" href="https://tvl.fyi/static/favicon.webp">
 <link rel="search" type="application/opensearchdescription+xml" title="TVL Search" href="https://at.tvl.fyi/opensearch.xml">
 <title>TVL Search</title>
-<body class="light">
+<script>
+  /* Initialise the state of all settings. */
+  function loadSettings() {
+      loadSetting(document.getElementById('cs-setting'), 'cs');
+  }
+
+  /* Initialise the state of a setting from a cookie. */
+  function loadSetting(checkbox, name) {
+      if (document.cookie.split(';').some(function(cookie) {
+          return cookie.indexOf(`${name}=true`) >= 0;
+      })) {
+          checkbox.checked = true;
+      }
+  }
+
+  /* Persist the state of a checkbox in a cookie */
+  function saveSetting(checkbox, name) {
+      console.log(`setting atward parameter '${name}' to ${checkbox.checked.toString()}`);
+      document.cookie = `${name}=${checkbox.checked.toString()};`;
+  }
+</script>
+<body class="light" onload="loadSettings();">
   <header>
     <h1><a class="blog-title" href="/">atward</a></h1>
     <hr/>
@@ -47,12 +68,28 @@
       <li><kbd>cs=true</kbd> - use Sourcegraph instead of cgit to view code</li>
     </ul>
   </p>
-  <p class="cheddar-callout cheddar-todo">
-    In <b>Firefox</b>, configuring query parameters is difficult as
-    users can not edit search engines directly. There are browser
-    extensions and other workarounds for this issue, but we do not
-    recommend any particular one.
+  <p>
+    In some browsers (like Firefox) users can not edit query
+    parameters for search engines. As an alternative configuration can
+    be supplied via cookies with the same names as the configuration
+    parameters.
+  </p>
+  <p>
+    The form below can set this configuration:
+    <form class="cheddar-callout cheddar-todo">
+      <input type="checkbox"
+             id="cs-setting"
+             onchange="saveSetting(this, 'cs');"
+             > Use Sourcegraph instead of cgit</input>
+    </form>
   </p>
+  <noscript>
+    <p class="cheddar-callout cheddar-warning">
+      The form above only works with Javascript enabled. Only a few
+      lines of Javascript are used, and they are licensed under a
+      free-software license (MIT).
+    </p>
+  </noscript>
 
   <h3>Source code</h3>
   <p>
diff --git a/web/atward/src/main.rs b/web/atward/src/main.rs
index 04beb02cd5d6..b29877c6c00e 100644
--- a/web/atward/src/main.rs
+++ b/web/atward/src/main.rs
@@ -5,7 +5,8 @@
 //! browsers and attempts to send users to useful locations based on
 //! their search query (falling back to another search engine).
 use regex::Regex;
-use rouille::Response;
+use rouille::input::cookies;
+use rouille::{Request, Response};
 
 /// A query handler supported by atward. It consists of a pattern on
 /// which to match and trigger the query, and a function to execute
@@ -23,6 +24,7 @@ struct Handler {
 }
 
 /// An Atward query supplied by a user.
+#[derive(Debug, PartialEq)]
 struct Query {
     /// Query string itself.
     query: String,
@@ -31,19 +33,38 @@ struct Query {
     cs: bool,
 }
 
+/// Helper function for setting a parameter based on a query
+/// parameter.
+fn query_setting(req: &Request, config: &mut bool, param: &str) {
+    match req.get_param(param) {
+        Some(s) if s == "true" => *config = true,
+        Some(s) if s == "false" => *config = false,
+        _ => {}
+    }
+}
+
 impl Query {
-    fn from_request(req: &rouille::Request) -> Option<Query> {
-        let query = match req.get_param("q") {
-            Some(q) => q,
+    fn from_request(req: &Request) -> Option<Query> {
+        // First extract the actual search query ...
+        let mut query = match req.get_param("q") {
+            Some(query) => Query { query, cs: false },
             None => return None,
         };
 
-        let cs = match req.get_param("cs") {
-            Some(s) if s == "true" => true,
-            _ => false,
-        };
+        // ... then apply settings to it. Settings in query parameters
+        // take precedence over cookies.
+        for cookie in cookies(req) {
+            match cookie {
+                ("cs", "true") => {
+                    query.cs = true;
+                }
+                _ => {}
+            }
+        }
 
-        Some(Query { query, cs })
+        query_setting(req, &mut query.cs, "cs");
+
+        Some(query)
     }
 }
 
@@ -228,4 +249,70 @@ mod tests {
             None
         );
     }
+
+    #[test]
+    fn request_to_query() {
+        assert_eq!(
+            Query::from_request(&Request::fake_http("GET", "/?q=b%2F42", vec![], vec![]))
+                .expect("request should parse to a query"),
+            Query {
+                query: "b/42".to_string(),
+                cs: false,
+            },
+        );
+
+        assert_eq!(
+            Query::from_request(&Request::fake_http("GET", "/", vec![], vec![])),
+            None
+        );
+    }
+
+    #[test]
+    fn settings_from_cookie() {
+        assert_eq!(
+            Query::from_request(&Request::fake_http(
+                "GET",
+                "/?q=b%2F42",
+                vec![("Cookie".to_string(), "cs=true;".to_string())],
+                vec![]
+            ))
+            .expect("request should parse to a query"),
+            Query {
+                query: "b/42".to_string(),
+                cs: true,
+            },
+        );
+    }
+
+    #[test]
+    fn settings_from_query_parameter() {
+        assert_eq!(
+            Query::from_request(&Request::fake_http(
+                "GET",
+                "/?q=b%2F42&cs=true",
+                vec![],
+                vec![]
+            ))
+            .expect("request should parse to a query"),
+            Query {
+                query: "b/42".to_string(),
+                cs: true,
+            },
+        );
+
+        // Query parameter should override cookie
+        assert_eq!(
+            Query::from_request(&Request::fake_http(
+                "GET",
+                "/?q=b%2F42&cs=false",
+                vec![("Cookie".to_string(), "cs=true;".to_string())],
+                vec![]
+            ))
+            .expect("request should parse to a query"),
+            Query {
+                query: "b/42".to_string(),
+                cs: false,
+            },
+        );
+    }
 }