use itertools::Itertools;
use web_sys::*;
use yew::prelude::*;
use super::expression_toolbar::*;
use crate::config::*;
use crate::dragdrop::*;
use crate::js::plugin::*;
use crate::model::*;
use crate::renderer::*;
use crate::session::*;
use crate::utils::ApiFuture;
use crate::*;
#[derive(Properties, Clone)]
pub struct InactiveColumnProps {
pub idx: usize,
pub visible: bool,
pub name: String,
pub dragdrop: DragDrop,
pub session: Session,
pub renderer: Renderer,
pub ondragend: Callback<()>,
pub onselect: Callback<()>,
}
impl PartialEq for InactiveColumnProps {
fn eq(&self, _rhs: &Self) -> bool {
false
}
}
derive_model!(Renderer, Session for InactiveColumnProps);
impl InactiveColumnProps {
pub fn activate_column(&self, name: String, shift: bool) {
let mut columns = self.session.get_view_config().columns.clone();
let max_cols = self
.renderer
.metadata()
.names
.as_ref()
.map_or(0, |x| x.len());
let last_filled = columns.iter().rposition(|x| !x.is_none()).unwrap();
columns.truncate(last_filled + 1);
let mode = self.renderer.metadata().mode;
if (mode == ColumnSelectMode::Select) ^ shift {
columns.clear();
} else {
columns.retain(|x| x.as_ref() != Some(&name));
}
columns.push(Some(name));
self.apply_columns(
columns
.into_iter()
.pad_using(max_cols, |_| None)
.collect::<Vec<_>>(),
);
}
fn apply_columns(&self, columns: Vec<Option<String>>) {
let config = ViewConfigUpdate {
columns: Some(columns),
..ViewConfigUpdate::default()
};
ApiFuture::spawn(self.update_and_render(config));
}
}
pub enum InactiveColumnMsg {
ActivateColumn(bool),
MouseEnter(bool),
MouseLeave(bool),
}
use InactiveColumnMsg::*;
#[derive(Default)]
pub struct InactiveColumn {
add_expression_ref: NodeRef,
mouseover: bool,
}
impl Component for InactiveColumn {
type Message = InactiveColumnMsg;
type Properties = InactiveColumnProps;
fn create(_ctx: &Context<Self>) -> Self {
Self::default()
}
fn update(&mut self, ctx: &Context<Self>, msg: InactiveColumnMsg) -> bool {
match msg {
ActivateColumn(shift_key) => {
ctx.props()
.activate_column(ctx.props().name.to_owned(), shift_key);
ctx.props().onselect.emit(());
false
}
MouseEnter(is_render) => {
self.mouseover = is_render;
is_render
}
MouseLeave(is_render) => {
self.mouseover = false;
is_render
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let col_type = ctx
.props()
.session
.metadata()
.get_column_table_type(&ctx.props().name)
.expect("Unknown column");
let add_column = ctx
.link()
.callback(|event: MouseEvent| InactiveColumnMsg::ActivateColumn(event.shift_key()));
let ondragend = ctx.props().ondragend.reform(|_| {});
let ondragstart = ctx.link().callback({
let event_name = ctx.props().name.to_owned();
let dragdrop = ctx.props().dragdrop.clone();
move |event: DragEvent| {
dragdrop.set_drag_image(&event).unwrap();
dragdrop.notify_drag_start(event_name.to_string(), DragEffect::Copy);
MouseLeave(false)
}
});
let onmouseout = ctx.link().callback(|_| MouseLeave(true));
let onmouseover = ctx
.link()
.callback(|event: MouseEvent| MouseEnter(event.which() == 0));
let is_expression = ctx
.props()
.session
.metadata()
.is_column_expression(&ctx.props().name);
let is_active_class = ctx.props().renderer.metadata().mode.css();
let mut class = classes!("column-selector-column");
if !ctx.props().visible {
class.push("column-selector-column-hidden");
}
if self.mouseover {
class.push("dragdrop-hover");
}
html! {
<div
class={ class }
{ onmouseover }
{ onmouseout }
data-index={ ctx.props().idx.to_string() }>
<span
class={ is_active_class }
onmousedown={ add_column }>
</span>
<div
class="column-selector-draggable column-selector-column-title"
draggable="true"
ref={ &self.add_expression_ref }
{ ondragstart }
{ ondragend }>
<div class="column-selector-column-border">
<span class={ format!("column_name {}", col_type) }>
{ &ctx.props().name }
</span>
<span class="column-selector--spacer"></span>
if is_expression {
<ExpressionToolbar
session={ &ctx.props().session }
renderer={ &ctx.props().renderer }
dragdrop={ &ctx.props().dragdrop }
name={ ctx.props().name.clone() }
add_expression_ref={ &self.add_expression_ref }>
</ExpressionToolbar>
}
</div>
</div>
</div>
}
}
}