Showing
9 changed files
with
202 additions
and
61 deletions
| @@ -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