Commit 8a73c4136d93e9413bc3899f09a2f8494eb6c9ee

Authored by Georg Hopp
1 parent b6c24761

Make all patches choosable

@@ -14,3 +14,9 @@ pub struct MarkdownJson { @@ -14,3 +14,9 @@ pub struct MarkdownJson {
14 pub date_created: String, 14 pub date_created: String,
15 pub date_updated: String, 15 pub date_updated: String,
16 } 16 }
  17 +
  18 +#[derive(Clone, Debug, Serialize, Deserialize)]
  19 +pub struct MarkdownDiffJson {
  20 + pub id: i32,
  21 + pub date_created: String,
  22 +}
No preview for this file type
1 -use std::error::Error as StdError;  
2 -use std::fmt; 1 +use std::{fmt::Display, pin::Pin};
3 2
4 use diesel::result; 3 use diesel::result;
  4 +use diffy::ParsePatchError;
5 use r2d2; 5 use r2d2;
6 6
  7 +type ParentError = Option<Pin<Box<dyn std::error::Error>>>;
  8 +
7 #[derive(Debug)] 9 #[derive(Debug)]
8 -pub(crate) enum Error {  
9 - DieselResult(result::Error),  
10 - DieselR2d2(r2d2::Error), 10 +pub(crate) struct Error {
  11 + source: ParentError,
  12 + message: String,
11 } 13 }
12 14
13 -impl fmt::Display for Error {  
14 - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {  
15 - match self {  
16 - Error::DieselR2d2(r) => write!(f, "{}", r),  
17 - Error::DieselResult(r) => write!(f, "{}", r),  
18 - } 15 +unsafe impl Send for Error {}
  16 +
  17 +pub(crate) type Result<T> = std::result::Result<T, Error>;
  18 +
  19 +impl std::error::Error for Error {
  20 + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
  21 + self.source.as_deref()
19 } 22 }
20 } 23 }
21 24
22 -impl StdError for Error {  
23 - fn source(&self) -> Option<&(dyn StdError + 'static)> { 25 +impl Display for Error {
  26 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 match self { 27 match self {
25 - Error::DieselR2d2(r) => Some(r),  
26 - Error::DieselResult(r) => Some(r), 28 + Error { source: Some(source), message } =>
  29 + write!(f, "{}: {}", message, source),
  30 + Error { source: None, message } => write!(f, "{}", message),
27 } 31 }
28 } 32 }
29 } 33 }
30 34
  35 +impl From<&str> for Error {
  36 + fn from(message: &str) -> Self {
  37 + Self { source: None, message: String::from(message) }
  38 + }
  39 +}
  40 +
31 impl From<result::Error> for Error { 41 impl From<result::Error> for Error {
32 - fn from(error: result::Error) -> Self {  
33 - Error::DieselResult(error) 42 + fn from(source: result::Error) -> Self {
  43 + Self { source: Some(Box::pin(source))
  44 + , message: String::from("Diesel Result Error")
  45 + }
34 } 46 }
35 } 47 }
36 48
37 impl From<r2d2::Error> for Error { 49 impl From<r2d2::Error> for Error {
38 - fn from(error: r2d2::Error) -> Self {  
39 - Error::DieselR2d2(error) 50 + fn from(source: r2d2::Error) -> Self {
  51 + Self { source: Some(Box::pin(source))
  52 + , message: String::from("Diesel Result Error")
  53 + }
  54 + }
  55 +}
  56 +
  57 +impl From<std::io::Error> for Error {
  58 + fn from(source: std::io::Error) -> Self {
  59 + Self { source: Some(Box::pin(source))
  60 + , message: String::from("IO Error")
  61 + }
  62 + }
  63 +}
  64 +
  65 +impl From<std::str::Utf8Error> for Error {
  66 + fn from(source: std::str::Utf8Error) -> Self {
  67 + Self { source: Some(Box::pin(source))
  68 + , message: String::from("IO Error")
  69 + }
  70 + }
  71 +}
  72 +
  73 +impl From<ParsePatchError> for Error {
  74 + fn from(source: ParsePatchError) -> Self {
  75 + Self { source: Some(Box::pin(source))
  76 + , message: String::from("IO Error")
  77 + }
40 } 78 }
41 } 79 }
@@ -6,7 +6,7 @@ mod models; @@ -6,7 +6,7 @@ mod models;
6 mod routes; 6 mod routes;
7 mod schema; 7 mod schema;
8 8
9 -use crate::routes::markdown::{get_markdowns, update_markdown}; 9 +use crate::routes::markdown::*;
10 use crate::routes::other::*; 10 use crate::routes::other::*;
11 use crate::routes::user::*; 11 use crate::routes::user::*;
12 12
@@ -40,6 +40,9 @@ async fn main() -> std::io::Result<()> { @@ -40,6 +40,9 @@ async fn main() -> std::io::Result<()> {
40 . route(web::get().to(get_markdown)) 40 . route(web::get().to(get_markdown))
41 . route(web::put().to(update_markdown)) 41 . route(web::put().to(update_markdown))
42 ) 42 )
  43 + . service( web::resource("/markdowns/{id}/patches")
  44 + . route(web::get().to(get_patches))
  45 + )
43 . service( web::resource("/users") 46 . service( web::resource("/users")
44 . route(web::get().to(get_users)) 47 . route(web::get().to(get_users))
45 . route(web::put().to(create_user)) 48 . route(web::put().to(create_user))
1 use std::sync::Arc; 1 use std::sync::Arc;
2 use crate::schema::*; 2 use crate::schema::*;
3 -use crate::error::Error; 3 +use crate::error::*;
4 use crate::Pool; 4 use crate::Pool;
  5 +use artshop_common::types::MarkdownDiffJson;
5 use artshop_common::types::MarkdownJson; 6 use artshop_common::types::MarkdownJson;
6 use diesel::prelude::*; 7 use diesel::prelude::*;
7 use diesel::{ 8 use diesel::{
@@ -75,6 +76,25 @@ impl<'a> From<&'a MarkdownJson> for MarkdownChange<'a> { @@ -75,6 +76,25 @@ impl<'a> From<&'a MarkdownJson> for MarkdownChange<'a> {
75 } 76 }
76 } 77 }
77 78
  79 +impl From<&MarkdownDiff> for MarkdownDiffJson {
  80 + fn from(md_diff: &MarkdownDiff) -> Self {
  81 + Self { id: md_diff.diff_id
  82 + , date_created: md_diff.date_created.to_owned()
  83 + }
  84 + }
  85 +}
  86 +
  87 +impl MarkdownDiff {
  88 + pub(crate) fn get_diff_as_string(&self) -> Result<String> {
  89 + let mut decoder = DeflateDecoder::new(Vec::new());
  90 +
  91 + decoder.write_all(self.diff.as_ref())?;
  92 + let decomp = decoder.finish()?;
  93 +
  94 + Ok(String::from(std::str::from_utf8(decomp.as_ref())?))
  95 + }
  96 +}
  97 +
78 pub(crate) enum _Action { 98 pub(crate) enum _Action {
79 Created(Markdown), 99 Created(Markdown),
80 Found(Markdown), 100 Found(Markdown),
@@ -82,7 +102,7 @@ pub(crate) enum _Action { @@ -82,7 +102,7 @@ pub(crate) enum _Action {
82 102
83 103
84 pub(crate) fn _create_markdown( pool: Arc<Pool> 104 pub(crate) fn _create_markdown( pool: Arc<Pool>
85 - , item: MarkdownJson ) -> Result<_Action, Error> { 105 + , item: MarkdownJson ) -> Result<_Action> {
86 use crate::schema::markdowns::dsl::*; 106 use crate::schema::markdowns::dsl::*;
87 let db_connection = pool.get()?; 107 let db_connection = pool.get()?;
88 108
@@ -111,7 +131,7 @@ pub(crate) fn _create_markdown( pool: Arc<Pool> @@ -111,7 +131,7 @@ pub(crate) fn _create_markdown( pool: Arc<Pool>
111 } 131 }
112 } 132 }
113 133
114 -pub(crate) fn get_markdowns(pool: Arc<Pool>) -> Result<Vec<Markdown>, Error> 134 +pub(crate) fn get_markdowns(pool: Arc<Pool>) -> Result<Vec<Markdown>>
115 { 135 {
116 use crate::schema::markdowns::dsl::*; 136 use crate::schema::markdowns::dsl::*;
117 let db_connection = pool.get()?; 137 let db_connection = pool.get()?;
@@ -120,10 +140,11 @@ pub(crate) fn get_markdowns(pool: Arc<Pool>) -> Result<Vec<Markdown>, Error> @@ -120,10 +140,11 @@ pub(crate) fn get_markdowns(pool: Arc<Pool>) -> Result<Vec<Markdown>, Error>
120 140
121 pub(crate) fn get_markdown( pool: Arc<Pool> 141 pub(crate) fn get_markdown( pool: Arc<Pool>
122 , ident: &str 142 , ident: &str
123 - , patch: Option<i32> ) -> Result<Markdown, Error> 143 + , patch: Option<i32> ) -> Result<Markdown>
124 { 144 {
125 use crate::schema::markdowns::dsl::*; 145 use crate::schema::markdowns::dsl::*;
126 use crate::schema::markdown_diffs::dsl::*; 146 use crate::schema::markdown_diffs::dsl::*;
  147 +
127 let db_connection = pool.get()?; 148 let db_connection = pool.get()?;
128 149
129 let mut markdown = markdowns 150 let mut markdown = markdowns
@@ -131,17 +152,16 @@ pub(crate) fn get_markdown( pool: Arc<Pool> @@ -131,17 +152,16 @@ pub(crate) fn get_markdown( pool: Arc<Pool>
131 . first::<Markdown>(&db_connection)?; 152 . first::<Markdown>(&db_connection)?;
132 153
133 if let Some(patch) = patch { 154 if let Some(patch) = patch {
134 - let result = markdown_diffs . filter(markdown_id.eq(markdown.id))  
135 - . filter(diff_id.ge(patch))  
136 - . order(diff_id.desc())  
137 - . load::<MarkdownDiff>(&db_connection)?; 155 + let result = markdown_diffs
  156 + . filter(markdown_id.eq(markdown.id))
  157 + . filter(diff_id.ge(patch))
  158 + . order(diff_id.desc())
  159 + . load::<MarkdownDiff>(&db_connection)?;
138 160
139 - let mut decoder = DeflateDecoder::new(Vec::new());  
140 for patch in result { 161 for patch in result {
141 - decoder.write_all(patch.diff.as_ref()).unwrap();  
142 - let decomp = decoder.reset(Vec::new()).unwrap();  
143 - let decomp = Patch::from_str(  
144 - std::str::from_utf8(decomp.as_ref()).unwrap()).unwrap(); 162 + let patch_data = patch.get_diff_as_string()?;
  163 + let decomp = Patch::from_str(&patch_data)?;
  164 +
145 markdown.content = apply(&markdown.content, &decomp).unwrap(); 165 markdown.content = apply(&markdown.content, &decomp).unwrap();
146 markdown.date_updated = patch.date_created; 166 markdown.date_updated = patch.date_created;
147 } 167 }
@@ -150,8 +170,27 @@ pub(crate) fn get_markdown( pool: Arc<Pool> @@ -150,8 +170,27 @@ pub(crate) fn get_markdown( pool: Arc<Pool>
150 Ok(markdown) 170 Ok(markdown)
151 } 171 }
152 172
  173 +pub(crate) fn get_patches( pool: Arc<Pool>
  174 + , ident: &str ) -> Result<Vec<MarkdownDiffJson>> {
  175 + use crate::schema::markdowns::dsl::*;
  176 + use crate::schema::markdown_diffs::dsl::*;
  177 +
  178 + let db_connection = pool.get()?;
  179 +
  180 + let markdown = markdowns
  181 + . filter(name.eq(ident))
  182 + . first::<Markdown>(&db_connection)?;
  183 +
  184 + Ok ( markdown_diffs . filter(markdown_id.eq(markdown.id))
  185 + . order(diff_id.desc())
  186 + . load::<MarkdownDiff>(&db_connection)?
  187 + . iter()
  188 + . map(|d| MarkdownDiffJson::from(d))
  189 + . collect() )
  190 +}
  191 +
153 pub(crate) fn _delete_markdown( pool: Arc<Pool> 192 pub(crate) fn _delete_markdown( pool: Arc<Pool>
154 - , ident: i32 ) -> Result<usize, Error> 193 + , ident: i32 ) -> Result<usize>
155 { 194 {
156 use crate::schema::markdowns::dsl::*; 195 use crate::schema::markdowns::dsl::*;
157 let db_connection = pool.get()?; 196 let db_connection = pool.get()?;
@@ -160,7 +199,7 @@ pub(crate) fn _delete_markdown( pool: Arc<Pool> @@ -160,7 +199,7 @@ pub(crate) fn _delete_markdown( pool: Arc<Pool>
160 199
161 pub(crate) fn update_markdown( pool: Arc<Pool> 200 pub(crate) fn update_markdown( pool: Arc<Pool>
162 , ident: String 201 , ident: String
163 - , mut item: MarkdownJson ) -> Result<Markdown, Error> 202 + , mut item: MarkdownJson ) -> Result<Markdown>
164 { 203 {
165 use crate::schema::markdowns::dsl::*; 204 use crate::schema::markdowns::dsl::*;
166 use crate::schema::markdown_diffs::dsl::*; 205 use crate::schema::markdown_diffs::dsl::*;
1 use std::sync::Arc; 1 use std::sync::Arc;
2 use crate::schema::*; 2 use crate::schema::*;
3 -use crate::error::Error; 3 +use crate::error::*;
4 use crate::Pool; 4 use crate::Pool;
5 use diesel::prelude::*; 5 use diesel::prelude::*;
6 use diesel::{ 6 use diesel::{
@@ -40,7 +40,7 @@ pub(crate) enum Action { @@ -40,7 +40,7 @@ pub(crate) enum Action {
40 40
41 41
42 pub(crate) fn create_user( pool: Arc<Pool> 42 pub(crate) fn create_user( pool: Arc<Pool>
43 - , item: UserJson ) -> Result<Action, Error> { 43 + , item: UserJson ) -> Result<Action> {
44 use crate::schema::users::dsl::*; 44 use crate::schema::users::dsl::*;
45 let db_connection = pool.get()?; 45 let db_connection = pool.get()?;
46 46
@@ -67,7 +67,7 @@ pub(crate) fn create_user( pool: Arc<Pool> @@ -67,7 +67,7 @@ pub(crate) fn create_user( pool: Arc<Pool>
67 } 67 }
68 } 68 }
69 69
70 -pub(crate) fn get_users(pool: Arc<Pool>) -> Result<Vec<User>, Error> 70 +pub(crate) fn get_users(pool: Arc<Pool>) -> Result<Vec<User>>
71 { 71 {
72 use crate::schema::users::dsl::*; 72 use crate::schema::users::dsl::*;
73 let db_connection = pool.get()?; 73 let db_connection = pool.get()?;
@@ -75,7 +75,7 @@ pub(crate) fn get_users(pool: Arc<Pool>) -> Result<Vec<User>, Error> @@ -75,7 +75,7 @@ pub(crate) fn get_users(pool: Arc<Pool>) -> Result<Vec<User>, Error>
75 } 75 }
76 76
77 pub(crate) fn get_user( pool: Arc<Pool> 77 pub(crate) fn get_user( pool: Arc<Pool>
78 - , ident: i32 ) -> Result<User, Error> 78 + , ident: i32 ) -> Result<User>
79 { 79 {
80 use crate::schema::users::dsl::*; 80 use crate::schema::users::dsl::*;
81 let db_connection = pool.get()?; 81 let db_connection = pool.get()?;
@@ -83,7 +83,7 @@ pub(crate) fn get_user( pool: Arc<Pool> @@ -83,7 +83,7 @@ pub(crate) fn get_user( pool: Arc<Pool>
83 } 83 }
84 84
85 pub(crate) fn delete_user( pool: Arc<Pool> 85 pub(crate) fn delete_user( pool: Arc<Pool>
86 - , ident: i32 ) -> Result<usize, Error> 86 + , ident: i32 ) -> Result<usize>
87 { 87 {
88 use crate::schema::users::dsl::*; 88 use crate::schema::users::dsl::*;
89 let db_connection = pool.get()?; 89 let db_connection = pool.get()?;
@@ -92,7 +92,7 @@ pub(crate) fn delete_user( pool: Arc<Pool> @@ -92,7 +92,7 @@ pub(crate) fn delete_user( pool: Arc<Pool>
92 92
93 pub(crate) fn update_user( pool: Arc<Pool> 93 pub(crate) fn update_user( pool: Arc<Pool>
94 , ident: i32 94 , ident: i32
95 - , item: UserJson ) -> Result<User, Error> 95 + , item: UserJson ) -> Result<User>
96 { 96 {
97 use crate::schema::users::dsl::*; 97 use crate::schema::users::dsl::*;
98 let db_connection = pool.get()?; 98 let db_connection = pool.get()?;
@@ -37,6 +37,19 @@ pub async fn get_markdown( pool: web::Data<Pool> @@ -37,6 +37,19 @@ pub async fn get_markdown( pool: web::Data<Pool>
37 ) 37 )
38 } 38 }
39 39
  40 +pub async fn get_patches( pool: web::Data<Pool>
  41 + , name: web::Path<String>
  42 + ) -> Result<HttpResponse, Error> {
  43 + let pool = pool.into_inner();
  44 + let name = name.into_inner();
  45 +
  46 + Ok( web::block(move || markdown::get_patches(pool, name.as_str()))
  47 + . await
  48 + . map(|patches| HttpResponse::Ok().json(patches))
  49 + . map_err(|_| HttpResponse::InternalServerError())?
  50 + )
  51 +}
  52 +
40 pub async fn update_markdown( pool: web::Data<Pool> 53 pub async fn update_markdown( pool: web::Data<Pool>
41 , name: web::Path<String> 54 , name: web::Path<String>
42 , item: web::Json<MarkdownJson> ) 55 , item: web::Json<MarkdownJson> )
1 use std::fmt::Display; 1 use std::fmt::Display;
2 2
3 -use artshop_common::types::MarkdownJson; 3 +use artshop_common::types::{MarkdownJson, MarkdownDiffJson};
4 4
5 use super::super::error::*; 5 use super::super::error::*;
6 use super::super::client::Client; 6 use super::super::client::Client;
@@ -56,6 +56,16 @@ impl Markdown { @@ -56,6 +56,16 @@ impl Markdown {
56 } 56 }
57 } 57 }
58 58
  59 + pub(crate) async fn patches(&self) -> Result<Vec<MarkdownDiffJson>> {
  60 + let url = format!("/api/v0/markdowns/{}/patches", self.json.name);
  61 + let (response, data) = self.client.get(url.as_str()).await?;
  62 +
  63 + match response.status() {
  64 + 200 => Ok(serde_json::from_str(&data)?),
  65 + status => Err(Self::status_error(status)),
  66 + }
  67 + }
  68 +
59 pub(crate) fn _to_html_string(&self) -> String { 69 pub(crate) fn _to_html_string(&self) -> String {
60 use pulldown_cmark::{Parser, Options, html}; 70 use pulldown_cmark::{Parser, Options, html};
61 71
@@ -15,21 +15,21 @@ enum AppLogic { @@ -15,21 +15,21 @@ enum AppLogic {
15 Update, 15 Update,
16 Toggle, 16 Toggle,
17 Store, 17 Store,
18 - Select(Option<i32>), 18 + Select,
  19 + Choose(Option<i32>),
19 Discard, 20 Discard,
20 } 21 }
21 22
22 async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic> 23 async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic>
23 - , tx_view: broadcast::Sender<String> 24 + , tx_logic: broadcast::Sender<AppLogic>
  25 + , tx_toggle: broadcast::Sender<bool>
  26 + , tx_patches: mpmc::Sender<ListPatch<ViewBuilder<Dom>>>
24 , mut rx_dom: broadcast::Receiver<Dom> ) 27 , mut rx_dom: broadcast::Receiver<Dom> )
25 { 28 {
26 let dom = rx_dom.next().await.unwrap(); 29 let dom = rx_dom.next().await.unwrap();
27 let mut show_edit = false; 30 let mut show_edit = false;
28 let mut md = Markdown::new("md-example").await.unwrap(); 31 let mut md = Markdown::new("md-example").await.unwrap();
29 32
30 - // TODO Only for experiments... remove when ready  
31 - md.read(Some(2)).await.unwrap();  
32 -  
33 let container = match dom.inner_read() { 33 let container = match dom.inner_read() {
34 Either::Left(dom_js) => 34 Either::Left(dom_js) =>
35 Some( ( dom_js 35 Some( ( dom_js
@@ -117,19 +117,38 @@ async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic> @@ -117,19 +117,38 @@ async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic>
117 AppLogic::Update => update(), 117 AppLogic::Update => update(),
118 AppLogic::Toggle => { 118 AppLogic::Toggle => {
119 show_edit = ! show_edit; 119 show_edit = ! show_edit;
120 - match show_edit {  
121 - true => tx_view . broadcast(String::from("block"))  
122 - . await.unwrap(),  
123 - false => tx_view . broadcast(String::from("none"))  
124 - . await.unwrap(),  
125 - }; 120 + tx_toggle.broadcast(show_edit).await.unwrap();
126 }, 121 },
127 AppLogic::Discard => { 122 AppLogic::Discard => {
128 set_md(md.json.content.as_str()); 123 set_md(md.json.content.as_str());
129 update(); 124 update();
130 }, 125 },
131 - AppLogic::Select(_id) => {  
132 - md.read(None).await.unwrap(); 126 + AppLogic::Select => {
  127 + let patches = md
  128 + . patches().await.unwrap()
  129 + . into_iter()
  130 + . map(|diff| {
  131 + let id = Some(diff.id);
  132 + let choose_filter = tx_logic
  133 + . sink()
  134 + . contra_map(move |_| AppLogic::Choose(id));
  135 + builder! {
  136 + <li><button on:click=choose_filter
  137 + value=format!("{}", diff.id.to_owned())>
  138 + {diff.date_created.to_owned()}
  139 + </button></li>
  140 + }});
  141 + let all = vec![builder! {
  142 + <li><button on:click=tx_logic.sink().contra_map(|_| AppLogic::Choose(None))>
  143 + "Current"
  144 + </button></li>
  145 + }].into_iter().chain(patches);
  146 +
  147 + let list_replace = ListPatch::splice(.., all);
  148 + tx_patches.send(list_replace).await.unwrap();
  149 + },
  150 + AppLogic::Choose(id) => {
  151 + md.read(id).await.unwrap();
133 set_md(md.json.content.as_str()); 152 set_md(md.json.content.as_str());
134 update(); 153 update();
135 }, 154 },
@@ -138,7 +157,8 @@ async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic> @@ -138,7 +157,8 @@ async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic>
138 } 157 }
139 158
140 fn editor_view( tx_logic: broadcast::Sender<AppLogic> 159 fn editor_view( tx_logic: broadcast::Sender<AppLogic>
141 - , rx_view: broadcast::Receiver<String> 160 + , rx_toggle: broadcast::Receiver<bool>
  161 + , rx_patches: mpmc::Receiver<ListPatch<ViewBuilder<Dom>>>
142 , tx_dom: broadcast::Sender<Dom> 162 , tx_dom: broadcast::Sender<Dom>
143 ) -> ViewBuilder<Dom> 163 ) -> ViewBuilder<Dom>
144 { 164 {
@@ -166,11 +186,16 @@ fn editor_view( tx_logic: broadcast::Sender<AppLogic> @@ -166,11 +186,16 @@ fn editor_view( tx_logic: broadcast::Sender<AppLogic>
166 . contra_map(|_| AppLogic::Toggle); 186 . contra_map(|_| AppLogic::Toggle);
167 let select_filter = tx_logic 187 let select_filter = tx_logic
168 . sink() 188 . sink()
169 - . contra_map(|_e| AppLogic::Select(None)); 189 + . contra_map(|_e| AppLogic::Select);
170 let discard_filter = tx_logic 190 let discard_filter = tx_logic
171 . sink() 191 . sink()
172 . contra_map(|_| AppLogic::Discard); 192 . contra_map(|_| AppLogic::Discard);
173 193
  194 + let toggle_map = rx_toggle
  195 + . map(|t| match t {
  196 + true => String::from("block"),
  197 + false => String::from("none") });
  198 +
174 builder! { 199 builder! {
175 <div class="input" 200 <div class="input"
176 style:width="33%" 201 style:width="33%"
@@ -178,12 +203,16 @@ fn editor_view( tx_logic: broadcast::Sender<AppLogic> @@ -178,12 +203,16 @@ fn editor_view( tx_logic: broadcast::Sender<AppLogic>
178 capture:view=tx_dom.sink()> 203 capture:view=tx_dom.sink()>
179 <div contenteditable="true" 204 <div contenteditable="true"
180 style:cursor="text" 205 style:cursor="text"
181 - style:display=("none", rx_view)> 206 + style:display=("none", toggle_map)>
182 <pre></pre> 207 <pre></pre>
183 </div> 208 </div>
184 <div> 209 <div>
185 <div> 210 <div>
  211 + <div>
186 <button on:click=select_filter>{select_icon()}</button> 212 <button on:click=select_filter>{select_icon()}</button>
  213 + <ul patch:children=rx_patches>
  214 + </ul>
  215 + </div>
187 <button on:click=store_filter>{save_icon()}</button> 216 <button on:click=store_filter>{save_icon()}</button>
188 <button on:click=discard_filter>{discard_icon()}</button> 217 <button on:click=discard_filter>{discard_icon()}</button>
189 <button on:click=toggle_filter>{edit_icon()}</button> 218 <button on:click=toggle_filter>{edit_icon()}</button>
@@ -203,9 +232,12 @@ pub async fn main() -> Result<(), JsValue> { @@ -203,9 +232,12 @@ pub async fn main() -> Result<(), JsValue> {
203 232
204 let (tx_dom, rx_dom) = broadcast::bounded(1); 233 let (tx_dom, rx_dom) = broadcast::bounded(1);
205 let (tx_logic, rx_logic) = broadcast::bounded(1); 234 let (tx_logic, rx_logic) = broadcast::bounded(1);
206 - let (tx_view, rx_view) = broadcast::bounded(1);  
207 - let comp = Component::from( editor_view(tx_logic, rx_view, tx_dom) )  
208 - . with_logic( editor_logic(rx_logic, tx_view, rx_dom) ); 235 + let (tx_toggle, rx_toggle) = broadcast::bounded(1);
  236 + let (tx_patches, rx_patches) = mpmc::bounded(1);
  237 +
  238 + let view = editor_view(tx_logic.clone(), rx_toggle, rx_patches, tx_dom);
  239 + let logic = editor_logic(rx_logic, tx_logic, tx_toggle, tx_patches, rx_dom);
  240 + let comp = Component::from(view).with_logic(logic);
209 241
210 let page = Component::from(builder! {{comp}}); 242 let page = Component::from(builder! {{comp}});
211 page.build()?.run() 243 page.build()?.run()
Please register or login to post a comment