Working on detect type
This commit is contained in:
parent
04f0620ba4
commit
1002f0c0e5
@ -18,3 +18,7 @@ strike {
|
|||||||
display: inline;
|
display: inline;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bq-rte {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
@ -40,7 +40,6 @@ pub fn on_click_change_day(field_id: crate::FieldId, date: chrono::NaiveDateTime
|
|||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
|
|
||||||
// info!("{:?}", date);
|
|
||||||
crate::Msg::StyledDateTimeInputChanged(
|
crate::Msg::StyledDateTimeInputChanged(
|
||||||
field_id,
|
field_id,
|
||||||
StyledDateTimeChanged::DayChanged(Some(date)),
|
StyledDateTimeChanged::DayChanged(Some(date)),
|
||||||
@ -113,6 +112,7 @@ pub fn on_click_change_select_selected(field_id: crate::FieldId, value: Option<u
|
|||||||
ev(Ev::Click, move |ev| {
|
ev(Ev::Click, move |ev| {
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
|
|
||||||
crate::Msg::StyledSelectChanged(field_id, StyledSelectChanged::Changed(value))
|
crate::Msg::StyledSelectChanged(field_id, StyledSelectChanged::Changed(value))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -120,6 +120,7 @@ pub fn on_click_change_select_selected(field_id: crate::FieldId, value: Option<u
|
|||||||
pub fn on_click_change_select_remove_multi(field_id: crate::FieldId, value: u32) -> EvHandler {
|
pub fn on_click_change_select_remove_multi(field_id: crate::FieldId, value: u32) -> EvHandler {
|
||||||
ev(Ev::Click, move |ev| {
|
ev(Ev::Click, move |ev| {
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
|
|
||||||
crate::Msg::StyledSelectChanged(field_id, StyledSelectChanged::RemoveMulti(value))
|
crate::Msg::StyledSelectChanged(field_id, StyledSelectChanged::RemoveMulti(value))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -162,6 +163,7 @@ fn noop(event: Ev) -> EvHandler {
|
|||||||
ev(event, |ev| {
|
ev(event, |ev| {
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
|
|
||||||
None as Option<crate::Msg>
|
None as Option<crate::Msg>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
use seed::prelude::*;
|
use seed::prelude::*;
|
||||||
use seed::*;
|
use seed::*;
|
||||||
use web_sys::MouseEvent;
|
use web_sys::{HtmlElement, MouseEvent};
|
||||||
|
|
||||||
use crate::components::styled_button::{ButtonVariant, StyledButton};
|
use crate::components::styled_button::{ButtonVariant, StyledButton};
|
||||||
use crate::components::styled_icon::{Icon, StyledIcon};
|
use crate::components::styled_icon::{Icon, StyledIcon};
|
||||||
use crate::components::styled_select::{SelectVariant, StyledSelect, StyledSelectState};
|
use crate::components::styled_select::{SelectVariant, StyledSelect, StyledSelectState};
|
||||||
use crate::components::styled_select_child::StyledSelectOption;
|
use crate::components::styled_select_child::StyledSelectOption;
|
||||||
use crate::components::styled_tooltip::{StyledTooltip, TooltipVariant};
|
use crate::components::styled_tooltip::{StyledTooltip, TooltipVariant};
|
||||||
use crate::{ButtonId, FieldId, Msg, RteField};
|
use crate::styled_select::StyledSelectChanged;
|
||||||
|
use crate::{BuildMsg, ButtonId, FieldId, Msg, RteField};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum HeadingSize {
|
pub enum HeadingSize {
|
||||||
@ -102,18 +103,17 @@ pub enum RteMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RteMsg {
|
impl RteMsg {
|
||||||
fn parse_str(ev: MouseEvent, target: &str, cols: u16, rows: u16) -> Self {
|
fn parse_str(ev: MouseEvent, action_name: &str, cols: u16, rows: u16) -> Self {
|
||||||
match target {
|
match action_name.trim() {
|
||||||
"bold" => Self::Bold,
|
"bold" => Self::Bold,
|
||||||
"italic" => Self::Italic,
|
"italic" => Self::Italic,
|
||||||
"underscore" => Self::Underscore,
|
"underscore" => Self::Underscore,
|
||||||
"strikethrough" => Self::Strikethrough,
|
"strikethrough" => Self::Strikethrough,
|
||||||
"listingDots" => Self::InsertUnorderedList,
|
"listingDots" => Self::InsertUnorderedList,
|
||||||
"listingNumber" => Self::InsertOrderedList,
|
"listingNumber" => Self::InsertOrderedList,
|
||||||
"subscript " => Self::Subscript,
|
"subscript" => Self::Subscript,
|
||||||
"superscript" => Self::Superscript,
|
"superscript" => Self::Superscript,
|
||||||
|
|
||||||
// "heading" => Self::InsertHeading(),
|
|
||||||
"table" => Self::TableSetVisibility(true),
|
"table" => Self::TableSetVisibility(true),
|
||||||
"codeAlt" => Self::InsertCode(true),
|
"codeAlt" => Self::InsertCode(true),
|
||||||
"closeRteTableTooltip" => Self::TableSetVisibility(false),
|
"closeRteTableTooltip" => Self::TableSetVisibility(false),
|
||||||
@ -124,7 +124,7 @@ impl RteMsg {
|
|||||||
_ => {
|
_ => {
|
||||||
let target = ev.target().unwrap();
|
let target = ev.target().unwrap();
|
||||||
let h = seed::to_html_el(&target);
|
let h = seed::to_html_el(&target);
|
||||||
error!("unknown rte command for element", h);
|
error!("unknown rte command for element", action_name, h);
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,6 +468,104 @@ impl StyledRteState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DetectFontStyle(FieldId);
|
||||||
|
|
||||||
|
impl BuildMsg for DetectFontStyle {
|
||||||
|
fn build(&self, element: &Option<web_sys::Element>) -> Option<Msg> {
|
||||||
|
let Some(el) = element else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let el = el.dyn_ref::<HtmlElement>();
|
||||||
|
let Some(mut el) = el else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let mut parent;
|
||||||
|
loop {
|
||||||
|
match el.tag_name().as_str() {
|
||||||
|
"BQ-RTE" => {
|
||||||
|
return Some(Msg::StyledSelectChanged(
|
||||||
|
self.0.clone(),
|
||||||
|
StyledSelectChanged::Changed(Some(HeadingSize::Normal.as_u32())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"H1" => {
|
||||||
|
return Some(Msg::StyledSelectChanged(
|
||||||
|
self.0.clone(),
|
||||||
|
StyledSelectChanged::Changed(Some(HeadingSize::H1.as_u32())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"H2" => {
|
||||||
|
return Some(Msg::StyledSelectChanged(
|
||||||
|
self.0.clone(),
|
||||||
|
StyledSelectChanged::Changed(Some(HeadingSize::H2.as_u32())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"H3" => {
|
||||||
|
return Some(Msg::StyledSelectChanged(
|
||||||
|
self.0.clone(),
|
||||||
|
StyledSelectChanged::Changed(Some(HeadingSize::H3.as_u32())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"H4" => {
|
||||||
|
return Some(Msg::StyledSelectChanged(
|
||||||
|
self.0.clone(),
|
||||||
|
StyledSelectChanged::Changed(Some(HeadingSize::H4.as_u32())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"H5" => {
|
||||||
|
return Some(Msg::StyledSelectChanged(
|
||||||
|
self.0.clone(),
|
||||||
|
StyledSelectChanged::Changed(Some(HeadingSize::H5.as_u32())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"H6" => {
|
||||||
|
return Some(Msg::StyledSelectChanged(
|
||||||
|
self.0.clone(),
|
||||||
|
StyledSelectChanged::Changed(Some(HeadingSize::H6.as_u32())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"BODY" => return None,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
parent = el.parent_element();
|
||||||
|
let Some(parent) = &parent else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(parent) = parent.dyn_ref::<HtmlElement>() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
el = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sender_allowed(&self, element: &Option<web_sys::Element>) -> bool {
|
||||||
|
let Some(el) = element else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let el = el.dyn_ref::<HtmlElement>();
|
||||||
|
let Some(mut el) = el else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let mut parent;
|
||||||
|
loop {
|
||||||
|
match el.tag_name().as_str() {
|
||||||
|
"BQ-RTE" => return false,
|
||||||
|
"BODY" => return false,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
parent = el.parent_element();
|
||||||
|
let Some(parent) = &parent else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(parent) = parent.dyn_ref::<HtmlElement>() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
el = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct StyledRte<'component> {
|
pub struct StyledRte<'component> {
|
||||||
pub field_id: FieldId,
|
pub field_id: FieldId,
|
||||||
pub table_tooltip: Option<&'component StyledRteTableState>,
|
pub table_tooltip: Option<&'component StyledRteTableState>,
|
||||||
@ -514,72 +612,32 @@ impl<'outer> StyledRte<'outer> {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let change_handler = {
|
let first_row = self.first_row(click_handler.clone());
|
||||||
let field_id = self.field_id.clone();
|
|
||||||
ev(Ev::Change, move |event| {
|
|
||||||
event
|
|
||||||
.target()
|
|
||||||
.as_ref()
|
|
||||||
.ok_or("Can't get event target reference")
|
|
||||||
.and_then(util::get_value)
|
|
||||||
.ok()
|
|
||||||
.and_then(|s| s.parse::<u16>().ok())
|
|
||||||
.map(|n| Msg::Rte(field_id, RteMsg::TableSetRows(n)))
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let first_row = Self::first_row(click_handler.clone());
|
let click_detect_font_style = mouse_ev(Ev::Click, |ev| {
|
||||||
let second_row = self.second_row(click_handler, change_handler);
|
let target = ev.target()?;
|
||||||
|
let el = to_html_el(&target);
|
||||||
|
tracing::info!("{:?} {:?}", el.tag_name(), el.id());
|
||||||
|
None as Option<Msg>
|
||||||
|
});
|
||||||
|
|
||||||
div![
|
div![
|
||||||
C!["styledRte"],
|
C!["styledRte"],
|
||||||
attrs![At::Id => id],
|
attrs![At::Id => id],
|
||||||
div![C!["bar"], first_row, second_row],
|
div![C!["bar"], first_row],
|
||||||
div![
|
div![
|
||||||
C!["editorWrapper"],
|
C!["editorWrapper"],
|
||||||
div![
|
custom![
|
||||||
|
Tag::from("bq-rte"),
|
||||||
C!["editor", self.field_id.to_str()],
|
C!["editor", self.field_id.to_str()],
|
||||||
attrs![At::ContentEditable => true],
|
attrs![At::ContentEditable => true],
|
||||||
],
|
click_detect_font_style
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_row(click_handler: EventHandler<Msg>) -> Node<Msg> {
|
fn first_row(&self, click_handler: EventHandler<Msg>) -> Node<Msg> {
|
||||||
let justify = {
|
|
||||||
let justify_all_button = Self::styled_rte_button(
|
|
||||||
"Justify All",
|
|
||||||
ButtonId::JustifyAll,
|
|
||||||
Icon::JustifyAll,
|
|
||||||
click_handler.clone(),
|
|
||||||
);
|
|
||||||
let justify_center_button = Self::styled_rte_button(
|
|
||||||
"Justify Center",
|
|
||||||
ButtonId::JustifyCenter,
|
|
||||||
Icon::JustifyCenter,
|
|
||||||
click_handler.clone(),
|
|
||||||
);
|
|
||||||
let justify_left_button = Self::styled_rte_button(
|
|
||||||
"Justify Left",
|
|
||||||
ButtonId::JustifyLeft,
|
|
||||||
Icon::JustifyLeft,
|
|
||||||
click_handler.clone(),
|
|
||||||
);
|
|
||||||
let justify_right_button = Self::styled_rte_button(
|
|
||||||
"Justify Right",
|
|
||||||
ButtonId::JustifyRight,
|
|
||||||
Icon::JustifyRight,
|
|
||||||
click_handler.clone(),
|
|
||||||
);
|
|
||||||
div![
|
|
||||||
C!["group justify"],
|
|
||||||
justify_all_button,
|
|
||||||
justify_center_button,
|
|
||||||
justify_left_button,
|
|
||||||
justify_right_button
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
let formatting = {
|
let formatting = {
|
||||||
let bold_button =
|
let bold_button =
|
||||||
Self::styled_rte_button("Bold", ButtonId::Bold, Icon::Bold, click_handler.clone());
|
Self::styled_rte_button("Bold", ButtonId::Bold, Icon::Bold, click_handler.clone());
|
||||||
@ -615,7 +673,7 @@ impl<'outer> StyledRte<'outer> {
|
|||||||
"Superscript",
|
"Superscript",
|
||||||
ButtonId::Superscript,
|
ButtonId::Superscript,
|
||||||
Icon::Superscript,
|
Icon::Superscript,
|
||||||
click_handler,
|
click_handler.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
div![
|
div![
|
||||||
@ -628,16 +686,19 @@ impl<'outer> StyledRte<'outer> {
|
|||||||
superscript_button,
|
superscript_button,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
let change_handler = {
|
||||||
div![C!["row firstRow"], formatting, justify]
|
let field_id = self.field_id.clone();
|
||||||
}
|
ev(Ev::Change, move |event| {
|
||||||
|
event
|
||||||
fn second_row(
|
.target()
|
||||||
&self,
|
.as_ref()
|
||||||
click_handler: EventHandler<Msg>,
|
.ok_or("Can't get event target reference")
|
||||||
change_handler: EventHandler<Msg>,
|
.and_then(util::get_value)
|
||||||
) -> Node<Msg> {
|
.ok()
|
||||||
let font_group = self.font_styles();
|
.and_then(|s| s.parse::<u16>().ok())
|
||||||
|
.map(|n| Msg::Rte(field_id, RteMsg::TableSetRows(n)))
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let insert_group = {
|
let insert_group = {
|
||||||
let table_tooltip = self.table_tooltip(click_handler.clone(), change_handler);
|
let table_tooltip = self.table_tooltip(click_handler.clone(), change_handler);
|
||||||
@ -679,7 +740,9 @@ impl<'outer> StyledRte<'outer> {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
div![C!["row secondRow"], font_group, insert_group,]
|
let font_group = self.font_styles();
|
||||||
|
|
||||||
|
div![C!["row firstRow"], font_group, formatting, insert_group]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn font_styles(&self) -> Node<Msg> {
|
fn font_styles(&self) -> Node<Msg> {
|
||||||
@ -689,13 +752,14 @@ impl<'outer> StyledRte<'outer> {
|
|||||||
} else {
|
} else {
|
||||||
HeadingSize::Normal
|
HeadingSize::Normal
|
||||||
};
|
};
|
||||||
|
let variant = SelectVariant::Empty;
|
||||||
let selected = vec![StyledSelectOption {
|
let selected = vec![StyledSelectOption {
|
||||||
name: Some(selected.as_str()),
|
name: Some(selected.as_str()),
|
||||||
icon: None,
|
icon: None,
|
||||||
text: Some(selected.as_str()),
|
text: Some(selected.as_str()),
|
||||||
value: selected.as_u32(),
|
value: selected.as_u32(),
|
||||||
class_list: "",
|
class_list: "",
|
||||||
variant: SelectVariant::Normal,
|
variant,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let options = Some(HeadingSize::all().iter().map(|h| StyledSelectOption {
|
let options = Some(HeadingSize::all().iter().map(|h| StyledSelectOption {
|
||||||
@ -704,12 +768,12 @@ impl<'outer> StyledRte<'outer> {
|
|||||||
text: Some(h.as_str()),
|
text: Some(h.as_str()),
|
||||||
value: h.as_u32(),
|
value: h.as_u32(),
|
||||||
class_list: "",
|
class_list: "",
|
||||||
variant: SelectVariant::Normal,
|
variant,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let font = StyledSelect {
|
let font = StyledSelect {
|
||||||
id: self.field_id.clone(),
|
id: self.field_id.clone(),
|
||||||
variant: SelectVariant::Normal,
|
variant,
|
||||||
dropdown_width: Some(96),
|
dropdown_width: Some(96),
|
||||||
name: "",
|
name: "",
|
||||||
valid: true,
|
valid: true,
|
||||||
|
@ -9,10 +9,8 @@ pub fn styled_tip<B>(letter: BrowserKey, model: &Model, builder: B) -> Node<Msg>
|
|||||||
where
|
where
|
||||||
B: BuildMsg + 'static,
|
B: BuildMsg + 'static,
|
||||||
{
|
{
|
||||||
model
|
model.key_triggers.insert(letter.clone(), Box::new(builder));
|
||||||
.key_triggers
|
|
||||||
.borrow_mut()
|
|
||||||
.insert(letter.clone(), Box::new(builder));
|
|
||||||
div![
|
div![
|
||||||
C!["proTip"],
|
C!["proTip"],
|
||||||
strong![C!["strong"], "Pro tip: "],
|
strong![C!["strong"], "Pro tip: "],
|
||||||
|
@ -63,10 +63,18 @@ pub enum OperationKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait BuildMsg: std::fmt::Debug {
|
pub trait BuildMsg: std::fmt::Debug {
|
||||||
fn build(&self) -> Msg;
|
fn build(&self, element: &Option<web_sys::Element>) -> Option<Msg>;
|
||||||
|
|
||||||
fn sender_allowed(&self, tag_name: Option<&str>) -> bool {
|
fn sender_allowed(&self, element: &Option<web_sys::Element>) -> bool {
|
||||||
tag_name == Some("BODY")
|
if element.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let tag = element.as_ref().map(|el| el.tag_name());
|
||||||
|
matches!(tag.as_deref(), Some("BODY"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_element(&self, _el: &web_sys::HtmlElement) -> Option<Msg> {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +282,7 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn view(model: &Model) -> Node<Msg> {
|
fn view(model: &Model) -> Node<Msg> {
|
||||||
model.key_triggers.borrow_mut().clear();
|
model.key_triggers.clear();
|
||||||
|
|
||||||
match model.page {
|
match model.page {
|
||||||
Page::Project
|
Page::Project
|
||||||
@ -390,27 +398,30 @@ fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
|||||||
);
|
);
|
||||||
let key_triggers = model.key_triggers.clone();
|
let key_triggers = model.key_triggers.clone();
|
||||||
|
|
||||||
let sender_clone = sender.clone();
|
{
|
||||||
shared::on_event::keydown(move |ev: KeyboardEvent| {
|
let sender_clone = sender.clone();
|
||||||
let sender = sender_clone.clone();
|
shared::on_event::keydown(move |ev: KeyboardEvent| {
|
||||||
let key_triggers = key_triggers.clone();
|
let sender = sender_clone.clone();
|
||||||
let event = seed::to_keyboard_event(&ev);
|
let key_triggers = key_triggers.clone();
|
||||||
|
let event = seed::to_keyboard_event(&ev);
|
||||||
|
|
||||||
let active = seed::document().active_element().map(|el| el.tag_name());
|
let active: Option<web_sys::Element> = seed::document().active_element();
|
||||||
|
|
||||||
let Ok(key) = event.key().parse::<BrowserKey>() else {
|
let Ok(key) = event.key().parse::<BrowserKey>() else {
|
||||||
return;
|
|
||||||
};
|
|
||||||
if let Some(b) = key_triggers.borrow().get(&key) {
|
|
||||||
if !b.sender_allowed(active.as_deref()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
ev.prevent_default();
|
if let Some(b) = key_triggers.0.borrow().get(&key) {
|
||||||
ev.stop_propagation();
|
if !b.sender_allowed(&active) {
|
||||||
let msg = b.build();
|
return;
|
||||||
sender.clone()(Some(msg));
|
}
|
||||||
};
|
ev.prevent_default();
|
||||||
});
|
ev.stop_propagation();
|
||||||
|
if let Some(msg) = b.build(&active) {
|
||||||
|
sender.clone()(Some(msg));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let sender_clone = sender.clone();
|
let sender_clone = sender.clone();
|
||||||
|
@ -25,17 +25,18 @@ use crate::{BuildMsg, FieldId, Msg};
|
|||||||
pub struct CloseCreateIssueModal;
|
pub struct CloseCreateIssueModal;
|
||||||
|
|
||||||
impl BuildMsg for CloseCreateIssueModal {
|
impl BuildMsg for CloseCreateIssueModal {
|
||||||
fn build(&self) -> Msg {
|
fn build(&self, element: &Option<web_sys::Element>) -> Option<Msg> {
|
||||||
Msg::ModalDropped
|
Some(Msg::ModalDropped)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sender_allowed(&self, tag_name: Option<&str>) -> bool {
|
fn sender_allowed(&self, element: &Option<web_sys::Element>) -> bool {
|
||||||
matches!(tag_name, Some("BODY") | Some("TEXTAREA"))
|
let tag_name = element.as_ref().map(|el| el.tag_name());
|
||||||
|
matches!(tag_name.as_deref(), Some("BODY") | Some("TEXTAREA"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
|
pub fn view(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
|
||||||
model.key_triggers.borrow_mut().insert(
|
model.key_triggers.insert(
|
||||||
BrowserKey::UiKey(UiKey::Escape),
|
BrowserKey::UiKey(UiKey::Escape),
|
||||||
Box::new(CloseCreateIssueModal),
|
Box::new(CloseCreateIssueModal),
|
||||||
);
|
);
|
||||||
|
@ -31,15 +31,16 @@ mod comments;
|
|||||||
pub struct CloseAddComment;
|
pub struct CloseAddComment;
|
||||||
|
|
||||||
impl BuildMsg for CloseAddComment {
|
impl BuildMsg for CloseAddComment {
|
||||||
fn build(&self) -> Msg {
|
fn build(&self, _element: &Option<web_sys::Element>) -> Option<Msg> {
|
||||||
Msg::ModalChanged(FieldChange::ToggleCommentForm(
|
Some(Msg::ModalChanged(FieldChange::ToggleCommentForm(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Comment(CommentFieldId::Body)),
|
FieldId::EditIssueModal(EditIssueModalSection::Comment(CommentFieldId::Body)),
|
||||||
false,
|
false,
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sender_allowed(&self, tag_name: Option<&str>) -> bool {
|
fn sender_allowed(&self, element: &Option<web_sys::Element>) -> bool {
|
||||||
matches!(tag_name, Some("TEXTAREA"))
|
let tag = element.as_ref().map(|el| el.tag_name());
|
||||||
|
tag.as_deref() == Some("TEXTAREA")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,11 +52,10 @@ pub fn view(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
|||||||
return Node::Empty;
|
return Node::Empty;
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
model
|
||||||
let mut b = model.key_triggers.borrow_mut();
|
.key_triggers
|
||||||
b.insert(BrowserKey::UiKey(UiKey::Escape), Box::new(CloseIssueModal));
|
.insert(BrowserKey::UiKey(UiKey::Escape), Box::new(CloseIssueModal))
|
||||||
b.insert(BrowserKey::UiKey(UiKey::Escape), Box::new(CloseAddComment));
|
.insert(BrowserKey::UiKey(UiKey::Escape), Box::new(CloseAddComment));
|
||||||
}
|
|
||||||
|
|
||||||
StyledModal {
|
StyledModal {
|
||||||
variant: ModalVariant::Center,
|
variant: ModalVariant::Center,
|
||||||
@ -294,12 +294,11 @@ fn left_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
|||||||
pub struct EnableCommentBuilder;
|
pub struct EnableCommentBuilder;
|
||||||
|
|
||||||
impl BuildMsg for EnableCommentBuilder {
|
impl BuildMsg for EnableCommentBuilder {
|
||||||
fn build(&self) -> Msg {
|
fn build(&self, _element: &Option<web_sys::Element>) -> Option<Msg> {
|
||||||
tracing::info!("{self:?}");
|
Some(Msg::ModalChanged(FieldChange::ToggleCommentForm(
|
||||||
Msg::ModalChanged(FieldChange::ToggleCommentForm(
|
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Comment(CommentFieldId::Body)),
|
FieldId::EditIssueModal(EditIssueModalSection::Comment(CommentFieldId::Body)),
|
||||||
true,
|
true,
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,9 +306,8 @@ impl BuildMsg for EnableCommentBuilder {
|
|||||||
pub struct CloseIssueModal;
|
pub struct CloseIssueModal;
|
||||||
|
|
||||||
impl BuildMsg for CloseIssueModal {
|
impl BuildMsg for CloseIssueModal {
|
||||||
fn build(&self) -> Msg {
|
fn build(&self, _element: &Option<web_sys::Element>) -> Option<Msg> {
|
||||||
tracing::info!("{self:?}");
|
Some(Msg::ModalDropped)
|
||||||
Msg::ModalDropped
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::HashMap;
|
use std::collections::hash_map::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use bitque_data::*;
|
use bitque_data::*;
|
||||||
use seed::app::Orders;
|
use seed::app::Orders;
|
||||||
@ -17,8 +19,8 @@ use crate::pages::reports_page::model::ReportsPage;
|
|||||||
use crate::pages::sign_in_page::model::SignInPage;
|
use crate::pages::sign_in_page::model::SignInPage;
|
||||||
use crate::pages::sign_up_page::model::SignUpPage;
|
use crate::pages::sign_up_page::model::SignUpPage;
|
||||||
use crate::pages::users_page::model::UsersPage;
|
use crate::pages::users_page::model::UsersPage;
|
||||||
use crate::{BuildMsg, Msg};
|
|
||||||
use crate::shared::keys::BrowserKey;
|
use crate::shared::keys::BrowserKey;
|
||||||
|
use crate::{BuildMsg, Msg};
|
||||||
|
|
||||||
pub trait IssueModal {
|
pub trait IssueModal {
|
||||||
fn epic_id_value(&self) -> Option<u32>;
|
fn epic_id_value(&self) -> Option<u32>;
|
||||||
@ -277,11 +279,31 @@ pub struct Model {
|
|||||||
pub epic_ids: Vec<EpicId>,
|
pub epic_ids: Vec<EpicId>,
|
||||||
pub epics_by_id: HashMap<EpicId, Epic>,
|
pub epics_by_id: HashMap<EpicId, Epic>,
|
||||||
|
|
||||||
pub key_triggers: std::rc::Rc<std::cell::RefCell<HashMap<BrowserKey, Box<dyn BuildMsg>>>>,
|
pub key_triggers: KeyTriggers,
|
||||||
pub distinct_key_up: crate::shared::on_event::Distinct,
|
pub distinct_key_up: crate::shared::on_event::Distinct,
|
||||||
pub show_extras: bool,
|
pub show_extras: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct KeyTriggers(pub Rc<RefCell<HashMap<BrowserKey, Box<dyn BuildMsg>>>>);
|
||||||
|
|
||||||
|
impl Default for KeyTriggers {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(Rc::new(RefCell::new(HashMap::with_capacity(64))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyTriggers {
|
||||||
|
pub fn insert(&self, key: BrowserKey, value: Box<dyn BuildMsg>) -> &Self {
|
||||||
|
self.0.borrow_mut().insert(key, value);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.0.borrow_mut().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
pub fn new(host_url: String, ws_url: String, page: Page) -> Self {
|
pub fn new(host_url: String, ws_url: String, page: Page) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -319,7 +341,7 @@ impl Model {
|
|||||||
show_extras: false,
|
show_extras: false,
|
||||||
modals_stack: vec![],
|
modals_stack: vec![],
|
||||||
modals: Modals::default(),
|
modals: Modals::default(),
|
||||||
key_triggers: std::rc::Rc::new(std::cell::RefCell::new(HashMap::with_capacity(20))),
|
key_triggers: KeyTriggers::default(),
|
||||||
distinct_key_up: crate::shared::on_event::distinct(),
|
distinct_key_up: crate::shared::on_event::distinct(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ mod filters;
|
|||||||
struct CreateIssueShortcut(i32);
|
struct CreateIssueShortcut(i32);
|
||||||
|
|
||||||
impl BuildMsg for CreateIssueShortcut {
|
impl BuildMsg for CreateIssueShortcut {
|
||||||
fn build(&self) -> Msg {
|
fn build(&self, _element: &Option<web_sys::Element>) -> Option<Msg> {
|
||||||
Msg::ModalOpened(ModalType::AddIssue(None))
|
Some(Msg::ModalOpened(ModalType::AddIssue(None)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +25,6 @@ pub fn view(model: &Model) -> Node<Msg> {
|
|||||||
{
|
{
|
||||||
model
|
model
|
||||||
.key_triggers
|
.key_triggers
|
||||||
.borrow_mut()
|
|
||||||
.insert(BrowserKey::Character('c'), Box::new(CreateIssueShortcut(0)));
|
.insert(BrowserKey::Character('c'), Box::new(CreateIssueShortcut(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user