tablo_core/schema/fields/builders/availability.rs
1//! The modifiers saying when a control renders disabled or not at all, beyond `disabled` and
2//! `disabled_on_edit`: on one of a record form's two forms, or while another field posts a value.
3
4use super::{ChoiceField, CustomField, FileField, TextField};
5use crate::schema::condition::{Condition, Watched};
6#[cfg(feature = "rich-text")]
7use crate::schema::fields::RichTextField;
8
9/// `hidden_on_create` and `hidden_on_edit`, on the builders of a record form's controls.
10macro_rules! form_visibility {
11 ($builder:ident) => {
12 impl<F: crate::schema::EditsRecords> $builder<F> {
13 /// Renders nothing for the field on the create form. The create stores the field's
14 /// `default`, else its blank answer: a required field with neither cannot mount. A
15 /// field hidden on both forms only ever stores that: set it in the record instead.
16 pub fn hidden_on_create(mut self) -> Self {
17 self.0.hidden.create = true;
18 self
19 }
20
21 /// Renders nothing for the field on the edit form, and keeps its stored value whatever
22 /// an edit posts: the create form sets the value, and no edit changes it, as
23 /// [`disabled_on_edit`](Self::disabled_on_edit) does without showing it.
24 pub fn hidden_on_edit(mut self) -> Self {
25 self.0.hidden.edit = true;
26 self
27 }
28 }
29 };
30}
31
32/// `disabled_when`, on the builders whose control a disabled fieldset disables: a rich text
33/// editor reads its state once, as it starts.
34macro_rules! conditional_disable {
35 ($builder:ident) => {
36 impl<F> $builder<F> {
37 /// Renders the control disabled while `watched` posts one of `values`: an option's
38 /// value, or `true` or `false` for a toggle. Disabled, the control posts nothing, so
39 /// an edit keeps the stored value and a create takes the field's `default`, else its
40 /// blank answer.
41 ///
42 /// ```rust
43 /// # #[derive(Debug, Clone, toasty::Model)]
44 /// # struct Order {
45 /// # #[key] #[auto] id: uuid::Uuid,
46 /// # status: String,
47 /// # total: i64,
48 /// # }
49 /// # use tablo_core::{Field, Schema};
50 /// let status = Field::choice(Order::fields().status()).options(["draft", "sent"]);
51 /// let total = Field::text(Order::fields().total()).disabled_when(&status, ["sent"]);
52 /// Schema::new((status, total));
53 /// ```
54 ///
55 /// - The browser enables and disables the control as the watched field changes, with no
56 /// request, through a disabled fieldset around it. An app's own
57 /// [`Control`](crate::extend::Control) follows it only through the form controls it
58 /// renders. Without JavaScript, the control starts as the form's initial values set
59 /// it, the stored ones on an edit, and stays that way.
60 /// - The panel reads a submission the same way and drops the field's posted key, and a
61 /// file field's carried upload, while the condition holds. The condition reads what
62 /// the user may post, so it is no access check:
63 /// [`ResourceDef::field_access`](crate::ResourceDef::field_access) is.
64 /// - Mounting refuses what it refuses for [`visible_when`](Self::visible_when): an
65 /// unplaced watched field, a value it never posts, a multiple choice, and a watched
66 /// field another condition hides while this one still shows. It also refuses a
67 /// required field with no non-blank `default`, which a create could not fill while
68 /// the condition holds, and a condition or a dependent choice watching this field: a
69 /// disabled control posts nothing, so the browser and the server would read different
70 /// values.
71 /// - A later call replaces an earlier one.
72 pub fn disabled_when(
73 mut self,
74 watched: &impl Watched<F>,
75 values: impl IntoIterator<Item = impl Into<String>>,
76 ) -> Self {
77 self.0.disabling = Some(Condition::new(watched, values));
78 self
79 }
80 }
81 };
82}
83
84form_visibility!(TextField);
85form_visibility!(ChoiceField);
86form_visibility!(FileField);
87form_visibility!(CustomField);
88#[cfg(feature = "rich-text")]
89form_visibility!(RichTextField);
90conditional_disable!(TextField);
91conditional_disable!(ChoiceField);
92conditional_disable!(FileField);
93conditional_disable!(CustomField);