mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-22 12:42:14 +00:00
197 lines
6.3 KiB
Rust
197 lines
6.3 KiB
Rust
|
use crate::exit;
|
||
|
use crate::store::*;
|
||
|
use crate::view::ViewMessage;
|
||
|
use crate::{Message, Scheduler};
|
||
|
use js_sys::Date;
|
||
|
|
||
|
use std::cell::RefCell;
|
||
|
use std::rc::Weak;
|
||
|
|
||
|
/// The controller of the application turns page state into functionality
|
||
|
pub struct Controller {
|
||
|
store: Store,
|
||
|
sched: RefCell<Option<Weak<Scheduler>>>,
|
||
|
active_route: String,
|
||
|
last_active_route: String,
|
||
|
}
|
||
|
|
||
|
/// Messages that represent the methods to be called on the Controller
|
||
|
pub enum ControllerMessage {
|
||
|
AddItem(String),
|
||
|
SetPage(String),
|
||
|
EditItemSave(String, String),
|
||
|
ToggleItem(String, bool),
|
||
|
EditItemCancel(String),
|
||
|
RemoveCompleted(),
|
||
|
RemoveItem(String),
|
||
|
ToggleAll(bool),
|
||
|
}
|
||
|
|
||
|
impl Controller {
|
||
|
pub fn new(store: Store, sched: Weak<Scheduler>) -> Controller {
|
||
|
Controller {
|
||
|
store,
|
||
|
sched: RefCell::new(Some(sched)),
|
||
|
active_route: "".into(),
|
||
|
last_active_route: "none".into(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Used by `Scheduler` to convert a `ControllerMessage` into a function call on a `Controller`
|
||
|
pub fn call(&mut self, method_name: ControllerMessage) {
|
||
|
use self::ControllerMessage::*;
|
||
|
match method_name {
|
||
|
AddItem(title) => self.add_item(title),
|
||
|
SetPage(hash) => self.set_page(hash),
|
||
|
EditItemSave(id, value) => self.edit_item_save(id, value),
|
||
|
EditItemCancel(id) => self.edit_item_cancel(id),
|
||
|
RemoveCompleted() => self.remove_completed_items(),
|
||
|
RemoveItem(id) => self.remove_item(&id),
|
||
|
ToggleAll(completed) => self.toggle_all(completed),
|
||
|
ToggleItem(id, completed) => self.toggle_item(id, completed),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn toggle_item(&mut self, id: String, completed: bool) {
|
||
|
self.toggle_completed(id, completed);
|
||
|
self._filter(completed);
|
||
|
}
|
||
|
|
||
|
fn add_message(&self, view_message: ViewMessage) {
|
||
|
if let Ok(sched) = self.sched.try_borrow_mut() {
|
||
|
if let Some(ref sched) = *sched {
|
||
|
if let Some(sched) = sched.upgrade() {
|
||
|
sched.add_message(Message::View(view_message));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn set_page(&mut self, raw: String) {
|
||
|
let route = raw.trim_left_matches("#/");
|
||
|
self.active_route = route.to_string();
|
||
|
self._filter(false);
|
||
|
self.add_message(ViewMessage::UpdateFilterButtons(route.to_string()));
|
||
|
}
|
||
|
|
||
|
/// Add an Item to the Store and display it in the list.
|
||
|
fn add_item(&mut self, title: String) {
|
||
|
self.store.insert(Item {
|
||
|
id: Date::now().to_string(),
|
||
|
title,
|
||
|
completed: false,
|
||
|
});
|
||
|
self.add_message(ViewMessage::ClearNewTodo());
|
||
|
self._filter(true);
|
||
|
}
|
||
|
|
||
|
/// Save an Item in edit.
|
||
|
fn edit_item_save(&mut self, id: String, title: String) {
|
||
|
if !title.is_empty() {
|
||
|
self.store.update(ItemUpdate::Title {
|
||
|
id: id.clone(),
|
||
|
title: title.clone(),
|
||
|
});
|
||
|
self.add_message(ViewMessage::EditItemDone(id.to_string(), title.to_string()));
|
||
|
} else {
|
||
|
self.remove_item(&id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Cancel the item editing mode.
|
||
|
fn edit_item_cancel(&mut self, id: String) {
|
||
|
let mut message = None;
|
||
|
if let Some(data) = self.store.find(ItemQuery::Id { id: id.clone() }) {
|
||
|
if let Some(todo) = data.get(0) {
|
||
|
let title = todo.title.to_string();
|
||
|
let citem = id.to_string();
|
||
|
message = Some(ViewMessage::EditItemDone(citem, title));
|
||
|
}
|
||
|
}
|
||
|
if let Some(message) = message {
|
||
|
self.add_message(message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Remove the data and elements related to an Item.
|
||
|
fn remove_item(&mut self, id: &String) {
|
||
|
self.store.remove(ItemQuery::Id { id: id.clone() });
|
||
|
self._filter(false);
|
||
|
let ritem = id.to_string();
|
||
|
self.add_message(ViewMessage::RemoveItem(ritem));
|
||
|
}
|
||
|
|
||
|
/// Remove all completed items.
|
||
|
fn remove_completed_items(&mut self) {
|
||
|
self.store.remove(ItemQuery::Completed { completed: true });
|
||
|
self._filter(true);
|
||
|
}
|
||
|
|
||
|
/// Update an Item in storage based on the state of completed.
|
||
|
fn toggle_completed(&mut self, id: String, completed: bool) {
|
||
|
self.store.update(ItemUpdate::Completed {
|
||
|
id: id.clone(),
|
||
|
completed,
|
||
|
});
|
||
|
let tid = id.to_string();
|
||
|
self.add_message(ViewMessage::SetItemComplete(tid, completed));
|
||
|
}
|
||
|
|
||
|
/// Set all items to complete or active.
|
||
|
fn toggle_all(&mut self, completed: bool) {
|
||
|
let mut vals = Vec::new();
|
||
|
self.store
|
||
|
.find(
|
||
|
ItemQuery::EmptyItemQuery,
|
||
|
).map(|data| {
|
||
|
for item in data.iter() {
|
||
|
vals.push(item.id.clone());
|
||
|
}
|
||
|
});
|
||
|
for id in vals.iter() {
|
||
|
self.toggle_completed(id.to_string(), completed);
|
||
|
}
|
||
|
self._filter(false);
|
||
|
}
|
||
|
|
||
|
/// Refresh the list based on the current route.
|
||
|
fn _filter(&mut self, force: bool) {
|
||
|
let route = &self.active_route;
|
||
|
|
||
|
if force || self.last_active_route != "" || &self.last_active_route != route {
|
||
|
let query = match route.as_str() {
|
||
|
"completed" => ItemQuery::Completed { completed: true },
|
||
|
"active" => ItemQuery::Completed { completed: false },
|
||
|
_ => ItemQuery::EmptyItemQuery,
|
||
|
};
|
||
|
let mut v = None;
|
||
|
{
|
||
|
let store = &mut self.store;
|
||
|
if let Some(res) = store.find(query) {
|
||
|
v = Some(res.into());
|
||
|
}
|
||
|
}
|
||
|
if let Some(res) = v {
|
||
|
self.add_message(ViewMessage::ShowItems(res));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if let Some((total, active, completed)) = self.store.count() {
|
||
|
self.add_message(ViewMessage::SetItemsLeft(active));
|
||
|
self.add_message(ViewMessage::SetClearCompletedButtonVisibility(
|
||
|
completed > 0,
|
||
|
));
|
||
|
self.add_message(ViewMessage::SetCompleteAllCheckbox(completed == total));
|
||
|
self.add_message(ViewMessage::SetMainVisibility(total > 0));
|
||
|
}
|
||
|
|
||
|
self.last_active_route = route.to_string();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Drop for Controller {
|
||
|
fn drop(&mut self) {
|
||
|
exit("calling drop on Controller");
|
||
|
}
|
||
|
}
|