Breaking change: renamed DerefFn to RefFn
This commit is contained in:
parent
bde76d90a4
commit
ef5a85aa2c
462
src/dom.rs
462
src/dom.rs
|
@ -1,4 +1,5 @@
|
|||
use std::ops::Deref;
|
||||
use std::convert::AsRef;
|
||||
use std::marker::PhantomData;
|
||||
use stdweb::{Reference, Value, JsSerialize, Once};
|
||||
use stdweb::unstable::{TryFrom, TryInto};
|
||||
use stdweb::web::{IEventTarget, INode, IElement, IHtmlElement, HtmlElement, Node, window, TextNode, EventTarget, Element};
|
||||
|
@ -18,38 +19,55 @@ use futures_channel::oneshot;
|
|||
use discard::{Discard, DiscardOnDrop};
|
||||
|
||||
|
||||
pub struct DerefFn<A, B> {
|
||||
pub struct RefFn<A, B, C> where B: ?Sized {
|
||||
value: A,
|
||||
callback: B,
|
||||
callback: C,
|
||||
return_value: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<A, B, C> DerefFn<A, C> where B: ?Sized, C: Fn(&A) -> &B {
|
||||
impl<A, B, C> RefFn<A, B, C> where B: ?Sized, C: Fn(&A) -> &B {
|
||||
#[inline]
|
||||
pub fn new(value: A, callback: C) -> Self {
|
||||
Self { value, callback }
|
||||
Self {
|
||||
value,
|
||||
callback,
|
||||
return_value: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn map<D, E>(self, callback: E) -> DerefFn<A, impl Fn(&A) -> &D>
|
||||
#[inline]
|
||||
pub fn call_ref(&self) -> &B {
|
||||
(self.callback)(&self.value)
|
||||
}
|
||||
|
||||
/*pub fn map<D, E>(self, callback: E) -> RefFn<A, impl Fn(&A) -> &D>
|
||||
where D: ?Sized,
|
||||
E: Fn(&B) -> &D {
|
||||
|
||||
let old_callback = self.callback;
|
||||
|
||||
DerefFn {
|
||||
RefFn {
|
||||
value: self.value,
|
||||
callback: move |value| callback(old_callback(value)),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
impl<A, B, C> Deref for DerefFn<A, C> where B: ?Sized, C: Fn(&A) -> &B {
|
||||
/*impl<A, B, C> Deref for RefFn<A, C> where B: ?Sized, C: Fn(&A) -> &B {
|
||||
type Target = B;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
(self.callback)(&self.value)
|
||||
self.call_ref()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/*impl<A, B, C> AsRef<B> for RefFn<A, C> where B: ?Sized, C: Fn(&A) -> &B {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &B {
|
||||
self.call_ref()
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
// TODO this should be in stdweb
|
||||
|
@ -207,7 +225,7 @@ pub fn text(value: &str) -> Dom {
|
|||
|
||||
// TODO should this inline ?
|
||||
pub fn text_signal<A, B>(value: B) -> Dom
|
||||
where A: IntoStr,
|
||||
where A: AsStr,
|
||||
B: IntoSignal<Item = A>,
|
||||
B::Signal: 'static {
|
||||
|
||||
|
@ -219,8 +237,7 @@ pub fn text_signal<A, B>(value: B) -> Dom
|
|||
let element = element.clone();
|
||||
|
||||
callbacks.after_remove(for_each(value.into_signal(), move |value| {
|
||||
let value = value.into_str();
|
||||
let value: &str = &value;
|
||||
let value = value.as_str();
|
||||
dom_operations::set_text(&element, value);
|
||||
}));
|
||||
}
|
||||
|
@ -293,21 +310,19 @@ pub fn create_element_ns<A: IElement>(name: &str, namespace: &str) -> A
|
|||
}
|
||||
|
||||
|
||||
fn set_option_str<A, B, C, F>(element: &A, callbacks: &mut Callbacks, value: C, mut f: F)
|
||||
fn set_option<A, B, C, D, F>(element: &A, callbacks: &mut Callbacks, value: D, mut f: F)
|
||||
where A: Clone + 'static,
|
||||
B: IntoOptionStr,
|
||||
C: IntoSignal<Item = B>,
|
||||
C::Signal: 'static,
|
||||
F: FnMut(&A, Option<&str>) + 'static {
|
||||
C: OptionStr<Output = B>,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static,
|
||||
F: FnMut(&A, Option<B>) + 'static {
|
||||
|
||||
let element = element.clone();
|
||||
|
||||
let mut is_set = false;
|
||||
|
||||
callbacks.after_remove(for_each(value.into_signal(), move |value| {
|
||||
let value = value.into_option_str();
|
||||
// TODO this is a bit hacky
|
||||
let value: Option<&str> = value.as_ref().map(|x| &**x);
|
||||
let value = value.into_option();
|
||||
|
||||
if value.is_some() {
|
||||
is_set = true;
|
||||
|
@ -323,6 +338,55 @@ fn set_option_str<A, B, C, F>(element: &A, callbacks: &mut Callbacks, value: C,
|
|||
}));
|
||||
}
|
||||
|
||||
fn set_style<A, B, C>(element: &A, name: &B, value: C, important: bool)
|
||||
where A: AsRef<Reference>,
|
||||
B: MultiStr,
|
||||
C: MultiStr {
|
||||
|
||||
let mut names = vec![];
|
||||
let mut values = vec![];
|
||||
|
||||
let okay = name.any(|name| {
|
||||
value.any(|value| {
|
||||
if dom_operations::try_set_style(element, name, value, important) {
|
||||
true
|
||||
|
||||
} else {
|
||||
names.push(name.to_string());
|
||||
values.push(value.to_string());
|
||||
false
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if !okay {
|
||||
// TODO maybe make this configurable
|
||||
panic!("style is incorrect:\n names: {}\n values: {}", names.join(", "), values.join(", "));
|
||||
}
|
||||
}
|
||||
|
||||
fn set_style_signal<A, B, C, D, E>(element: &A, callbacks: &mut Callbacks, name: B, value: E, important: bool)
|
||||
where A: AsRef<Reference> + Clone + 'static,
|
||||
B: MultiStr + 'static,
|
||||
C: MultiStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
set_option(element, callbacks, value, move |element, value| {
|
||||
match value {
|
||||
Some(value) => {
|
||||
set_style(element, &name, value, important);
|
||||
},
|
||||
None => {
|
||||
name.each(|name| {
|
||||
dom_operations::remove_style(element, name);
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
pub struct DomBuilder<A> {
|
||||
element: A,
|
||||
|
@ -426,31 +490,36 @@ impl<A: Into<Node>> DomBuilder<A> {
|
|||
// TODO make this JsSerialize rather than AsRef<Reference> ?
|
||||
impl<A: AsRef<Reference>> DomBuilder<A> {
|
||||
#[inline]
|
||||
pub fn property<B: JsSerialize>(self, name: &str, value: B) -> Self {
|
||||
dom_operations::set_property(&self.element, name, value);
|
||||
pub fn property<B, C>(self, name: B, value: C) -> Self where B: MultiStr, C: JsSerialize {
|
||||
name.each(|name| {
|
||||
dom_operations::set_property(&self.element, name, &value);
|
||||
});
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: AsRef<Reference> + Clone + 'static> DomBuilder<A> {
|
||||
fn set_property_signal<B, C>(&mut self, name: &str, value: C)
|
||||
where B: JsSerialize,
|
||||
C: IntoSignal<Item = B>,
|
||||
C::Signal: 'static {
|
||||
fn set_property_signal<B, C, D>(&mut self, name: B, value: D)
|
||||
where B: MultiStr + 'static,
|
||||
C: JsSerialize,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
|
||||
let element = self.element.clone();
|
||||
let name = name.to_owned();
|
||||
|
||||
self.callbacks.after_remove(for_each(value.into_signal(), move |value| {
|
||||
dom_operations::set_property(&element, &name, value);
|
||||
name.each(|name| {
|
||||
dom_operations::set_property(&element, name, &value);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn property_signal<B, C>(mut self, name: &str, value: C) -> Self
|
||||
where B: JsSerialize,
|
||||
C: IntoSignal<Item = B>,
|
||||
C::Signal: 'static {
|
||||
pub fn property_signal<B, C, D>(mut self, name: B, value: D) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: JsSerialize,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
|
||||
self.set_property_signal(name, value);
|
||||
self
|
||||
|
@ -497,84 +566,115 @@ impl<A: INode + Clone + 'static> DomBuilder<A> {
|
|||
|
||||
impl<A: IElement> DomBuilder<A> {
|
||||
#[inline]
|
||||
pub fn attribute(self, name: &str, value: &str) -> Self {
|
||||
dom_operations::set_attribute(&self.element, name, value);
|
||||
pub fn attribute<B>(self, name: B, value: &str) -> Self where B: MultiStr {
|
||||
name.each(|name| {
|
||||
dom_operations::set_attribute(&self.element, name, value);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn attribute_namespace(self, namespace: &str, name: &str, value: &str) -> Self {
|
||||
dom_operations::set_attribute_ns(&self.element, namespace, name, value);
|
||||
pub fn attribute_namespace<B>(self, namespace: &str, name: B, value: &str) -> Self where B: MultiStr {
|
||||
name.each(|name| {
|
||||
dom_operations::set_attribute_ns(&self.element, namespace, name, value);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn class(self, name: &str) -> Self {
|
||||
dom_operations::add_class(&self.element, name);
|
||||
pub fn class<B>(self, name: B) -> Self where B: MultiStr {
|
||||
name.each(|name| {
|
||||
dom_operations::add_class(&self.element, name);
|
||||
});
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: IElement + Clone + 'static> DomBuilder<A> {
|
||||
fn set_attribute_signal<B, C>(&mut self, name: &str, value: C)
|
||||
where B: IntoOptionStr,
|
||||
C: IntoSignal<Item = B>,
|
||||
C::Signal: 'static {
|
||||
fn set_attribute_signal<B, C, D, E>(&mut self, name: B, value: E)
|
||||
where B: MultiStr + 'static,
|
||||
C: AsStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
let name = name.to_owned();
|
||||
|
||||
set_option_str(&self.element, &mut self.callbacks, value, move |element, value| {
|
||||
set_option(&self.element, &mut self.callbacks, value, move |element, value| {
|
||||
match value {
|
||||
Some(value) => dom_operations::set_attribute(element, &name, value),
|
||||
None => dom_operations::remove_attribute(element, &name),
|
||||
Some(value) => {
|
||||
let value = value.as_str();
|
||||
|
||||
name.each(|name| {
|
||||
dom_operations::set_attribute(element, &name, value);
|
||||
});
|
||||
},
|
||||
None => {
|
||||
name.each(|name| {
|
||||
dom_operations::remove_attribute(element, &name)
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub fn attribute_signal<B, C>(mut self, name: &str, value: C) -> Self
|
||||
where B: IntoOptionStr,
|
||||
C: IntoSignal<Item = B>,
|
||||
C::Signal: 'static {
|
||||
pub fn attribute_signal<B, C, D, E>(mut self, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: AsStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
self.set_attribute_signal(name, value);
|
||||
self
|
||||
}
|
||||
|
||||
fn set_attribute_namespace_signal<B, C>(&mut self, namespace: &str, name: &str, value: C)
|
||||
where B: IntoOptionStr,
|
||||
C: IntoSignal<Item = B>,
|
||||
C::Signal: 'static {
|
||||
fn set_attribute_namespace_signal<B, C, D, E>(&mut self, namespace: &str, name: B, value: E)
|
||||
where B: MultiStr + 'static,
|
||||
C: AsStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
let name = name.to_owned();
|
||||
let namespace = namespace.to_owned();
|
||||
|
||||
set_option_str(&self.element, &mut self.callbacks, value, move |element, value| {
|
||||
set_option(&self.element, &mut self.callbacks, value, move |element, value| {
|
||||
match value {
|
||||
Some(value) => dom_operations::set_attribute_ns(element, &namespace, &name, value),
|
||||
None => dom_operations::remove_attribute_ns(element, &namespace, &name),
|
||||
Some(value) => {
|
||||
let value = value.as_str();
|
||||
|
||||
name.each(|name| {
|
||||
dom_operations::set_attribute_ns(element, &namespace, &name, value);
|
||||
});
|
||||
},
|
||||
None => {
|
||||
name.each(|name| {
|
||||
dom_operations::remove_attribute_ns(element, &namespace, &name);
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn attribute_namespace_signal<B, C>(mut self, namespace: &str, name: &str, value: C) -> Self
|
||||
where B: IntoOptionStr,
|
||||
C: IntoSignal<Item = B>,
|
||||
C::Signal: 'static {
|
||||
pub fn attribute_namespace_signal<B, C, D, E>(mut self, namespace: &str, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: AsStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
self.set_attribute_namespace_signal(namespace, name, value);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
fn set_class_signal<B>(&mut self, name: &str, value: B)
|
||||
where B: IntoSignal<Item = bool>,
|
||||
B::Signal: 'static {
|
||||
fn set_class_signal<B, C>(&mut self, name: B, value: C)
|
||||
where B: MultiStr + 'static,
|
||||
C: IntoSignal<Item = bool>,
|
||||
C::Signal: 'static {
|
||||
|
||||
let element = self.element.clone();
|
||||
let name = name.to_owned();
|
||||
|
||||
let mut is_set = false;
|
||||
|
||||
|
@ -582,29 +682,36 @@ impl<A: IElement + Clone + 'static> DomBuilder<A> {
|
|||
if value {
|
||||
if !is_set {
|
||||
is_set = true;
|
||||
dom_operations::add_class(&element, &name);
|
||||
|
||||
name.each(|name| {
|
||||
dom_operations::add_class(&element, name);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
if is_set {
|
||||
is_set = false;
|
||||
dom_operations::remove_class(&element, &name);
|
||||
|
||||
name.each(|name| {
|
||||
dom_operations::remove_class(&element, name);
|
||||
});
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn class_signal<B>(mut self, name: &str, value: B) -> Self
|
||||
where B: IntoSignal<Item = bool>,
|
||||
B::Signal: 'static {
|
||||
pub fn class_signal<B, C>(mut self, name: B, value: C) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: IntoSignal<Item = bool>,
|
||||
C::Signal: 'static {
|
||||
|
||||
self.set_class_signal(name, value);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
// TODO generalize IntoOptionStr ?
|
||||
// TODO use OptionStr ?
|
||||
fn set_scroll_signal<B, F>(&mut self, signal: B, mut f: F)
|
||||
where B: IntoSignal<Item = Option<f64>>,
|
||||
B::Signal: 'static,
|
||||
|
@ -639,52 +746,44 @@ impl<A: IElement + Clone + 'static> DomBuilder<A> {
|
|||
|
||||
impl<A: IHtmlElement> DomBuilder<A> {
|
||||
#[inline]
|
||||
pub fn style<B: StyleName>(self, name: B, value: &str) -> Self {
|
||||
name.set_style(&self.element, value, false);
|
||||
pub fn style<B, C>(self, name: B, value: C) -> Self
|
||||
where B: MultiStr,
|
||||
C: MultiStr {
|
||||
set_style(&self.element, &name, value, false);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_important<B: StyleName>(self, name: B, value: &str) -> Self {
|
||||
name.set_style(&self.element, value, true);
|
||||
pub fn style_important<B, C>(self, name: B, value: C) -> Self
|
||||
where B: MultiStr,
|
||||
C: MultiStr {
|
||||
set_style(&self.element, &name, value, true);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: IHtmlElement + Clone + 'static> DomBuilder<A> {
|
||||
fn set_style_signal<B, C, D>(&mut self, name: B, value: D, important: bool)
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
|
||||
set_option_str(&self.element, &mut self.callbacks, value, move |element, value| {
|
||||
match value {
|
||||
Some(value) => name.set_style(element, value, important),
|
||||
None => name.remove_style(element),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_signal<B, C, D>(mut self, name: B, value: D) -> Self
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
pub fn style_signal<B, C, D, E>(mut self, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: MultiStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
self.set_style_signal(name, value, false);
|
||||
set_style_signal(&self.element, &mut self.callbacks, name, value, false);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_important_signal<B, C, D>(mut self, name: B, value: D) -> Self
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
pub fn style_important_signal<B, C, D, E>(mut self, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: MultiStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
self.set_style_signal(name, value, true);
|
||||
set_style_signal(&self.element, &mut self.callbacks, name, value, true);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -767,51 +866,42 @@ impl StylesheetBuilder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style<B: StyleName>(self, name: B, value: &str) -> Self {
|
||||
name.set_style(&self.element, value, false);
|
||||
pub fn style<B, C>(self, name: B, value: C) -> Self
|
||||
where B: MultiStr,
|
||||
C: MultiStr {
|
||||
set_style(&self.element, &name, value, false);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_important<B: StyleName>(self, name: B, value: &str) -> Self {
|
||||
name.set_style(&self.element, value, true);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
fn set_style_signal<B, C, D>(&mut self, name: B, value: D, important: bool)
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
|
||||
set_option_str(&self.element, &mut self.callbacks, value, move |element, value| {
|
||||
match value {
|
||||
Some(value) => name.set_style(element, value, important),
|
||||
None => name.remove_style(element),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_signal<B, C, D>(mut self, name: B, value: D) -> Self
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
|
||||
self.set_style_signal(name, value, false);
|
||||
pub fn style_important<B, C>(self, name: B, value: C) -> Self
|
||||
where B: MultiStr,
|
||||
C: MultiStr {
|
||||
set_style(&self.element, &name, value, true);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_important_signal<B, C, D>(mut self, name: B, value: D) -> Self
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
pub fn style_signal<B, C, D, E>(mut self, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: MultiStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
self.set_style_signal(name, value, true);
|
||||
set_style_signal(&self.element, &mut self.callbacks, name, value, false);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_important_signal<B, C, D, E>(mut self, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: MultiStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
set_style_signal(&self.element, &mut self.callbacks, name, value, true);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -861,34 +951,40 @@ impl ClassBuilder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style<B: StyleName>(mut self, name: B, value: &str) -> Self {
|
||||
pub fn style<B, C>(mut self, name: B, value: C) -> Self
|
||||
where B: MultiStr,
|
||||
C: MultiStr {
|
||||
self.stylesheet = self.stylesheet.style(name, value);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_important<B: StyleName>(mut self, name: B, value: &str) -> Self {
|
||||
pub fn style_important<B, C>(mut self, name: B, value: C) -> Self
|
||||
where B: MultiStr,
|
||||
C: MultiStr {
|
||||
self.stylesheet = self.stylesheet.style_important(name, value);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_signal<B, C, D>(mut self, name: B, value: D) -> Self
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
pub fn style_signal<B, C, D, E>(mut self, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: MultiStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
self.stylesheet = self.stylesheet.style_signal(name, value);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn style_important_signal<B, C, D>(mut self, name: B, value: D) -> Self
|
||||
where B: StyleName + 'static,
|
||||
C: IntoOptionStr,
|
||||
D: IntoSignal<Item = C>,
|
||||
D::Signal: 'static {
|
||||
pub fn style_important_signal<B, C, D, E>(mut self, name: B, value: E) -> Self
|
||||
where B: MultiStr + 'static,
|
||||
C: MultiStr,
|
||||
D: OptionStr<Output = C>,
|
||||
E: IntoSignal<Item = D>,
|
||||
E::Signal: 'static {
|
||||
|
||||
self.stylesheet = self.stylesheet.style_important_signal(name, value);
|
||||
self
|
||||
|
@ -906,7 +1002,7 @@ impl ClassBuilder {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{create_element_ns, DomBuilder, HTML_NAMESPACE, text_signal, DerefFn};
|
||||
use super::{create_element_ns, DomBuilder, HTML_NAMESPACE, text_signal, RefFn};
|
||||
use futures_signals::signal::{always, SignalExt};
|
||||
use stdweb::web::{HtmlElement, IHtmlElement};
|
||||
|
||||
|
@ -925,7 +1021,7 @@ mod tests {
|
|||
fn text_signal_types() {
|
||||
text_signal(always("foo"));
|
||||
text_signal(always("foo".to_owned()));
|
||||
text_signal(always("foo".to_owned()).map(|x| DerefFn::new(x, |x| x.as_str())));
|
||||
text_signal(always("foo".to_owned()).map(|x| RefFn::new(x, |x| x.as_str())));
|
||||
//text_signal(always(Arc::new("foo")));
|
||||
//text_signal(always(Arc::new("foo".to_owned())));
|
||||
//text_signal(always(Rc::new("foo")));
|
||||
|
@ -936,24 +1032,74 @@ mod tests {
|
|||
//text_signal(always(Cow::Owned::<String>("foo".to_owned())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn property_signal_types() {
|
||||
let _a: DomBuilder<HtmlElement> = DomBuilder::new(create_element_ns("div", HTML_NAMESPACE))
|
||||
.property("foo", "hi")
|
||||
.property("foo", 5)
|
||||
.property(["foo", "-webkit-foo", "-ms-foo"], "hi")
|
||||
|
||||
.property_signal("foo", always("hi"))
|
||||
.property_signal("foo", always(5))
|
||||
.property_signal("foo", always(Some("hi")))
|
||||
|
||||
.property_signal(["foo", "-webkit-foo", "-ms-foo"], always("hi"))
|
||||
.property_signal(["foo", "-webkit-foo", "-ms-foo"], always(5))
|
||||
.property_signal(["foo", "-webkit-foo", "-ms-foo"], always(Some("hi")))
|
||||
;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn attribute_signal_types() {
|
||||
let _a: DomBuilder<HtmlElement> = DomBuilder::new(create_element_ns("div", HTML_NAMESPACE))
|
||||
.attribute("foo", "hi")
|
||||
.attribute(["foo", "-webkit-foo", "-ms-foo"], "hi")
|
||||
|
||||
.attribute_signal("foo", always("hi"))
|
||||
.attribute_signal("foo", always(Some("hi")))
|
||||
|
||||
.attribute_signal(["foo", "-webkit-foo", "-ms-foo"], always("hi"))
|
||||
.attribute_signal(["foo", "-webkit-foo", "-ms-foo"], always(Some("hi")))
|
||||
;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_signal_types() {
|
||||
let _a: DomBuilder<HtmlElement> = DomBuilder::new(create_element_ns("div", HTML_NAMESPACE))
|
||||
.class("foo")
|
||||
.class(["foo", "-webkit-foo", "-ms-foo"])
|
||||
|
||||
.class_signal("foo", always(true))
|
||||
.class_signal(["foo", "-webkit-foo", "-ms-foo"], always(true))
|
||||
;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn style_signal_types() {
|
||||
let _a: DomBuilder<HtmlElement> = DomBuilder::new(create_element_ns("div", HTML_NAMESPACE))
|
||||
.style_signal("foo", always("bar"))
|
||||
.style_signal("foo", always("bar".to_owned()))
|
||||
.style_signal("foo", always("bar".to_owned()).map(|x| DerefFn::new(x, |x| x.as_str())))
|
||||
.style_signal("foo", always("bar".to_owned()).map(|x| RefFn::new(x, |x| x.as_str())))
|
||||
|
||||
//.style_signal(vec!["-moz-foo", "-webkit-foo", "foo"].as_slice(), always("bar"))
|
||||
//.style_signal(vec!["-moz-foo", "-webkit-foo", "foo"].as_slice(), always("bar".to_owned()))
|
||||
//.style_signal(vec!["-moz-foo", "-webkit-foo", "foo"].as_slice(), always("bar".to_owned()).map(|x| RefFn::new(x, |x| x.as_str())))
|
||||
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always("bar"))
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always("bar".to_owned()))
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always("bar".to_owned()).map(|x| DerefFn::new(x, |x| x.as_str())))
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always("bar".to_owned()).map(|x| RefFn::new(x, |x| x.as_str())))
|
||||
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always(["bar", "qux"]))
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always(["bar".to_owned(), "qux".to_owned()]))
|
||||
//.style_signal(["-moz-foo", "-webkit-foo", "foo"], always(("bar".to_owned(), "qux".to_owned())).map(|x| RefFn::new(x, |x| [x.0.as_str(), x.1.as_str()])))
|
||||
|
||||
.style_signal("foo", always(Some("bar")))
|
||||
.style_signal("foo", always(Some("bar".to_owned())))
|
||||
.style_signal("foo", always("bar".to_owned()).map(|x| Some(DerefFn::new(x, |x| x.as_str()))))
|
||||
.style_signal("foo", always("bar".to_owned()).map(|x| Some(RefFn::new(x, |x| x.as_str()))))
|
||||
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always(Some("bar")))
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always(Some("bar".to_owned())))
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always("bar".to_owned()).map(|x| Some(DerefFn::new(x, |x| x.as_str()))))
|
||||
.style_signal(["-moz-foo", "-webkit-foo", "foo"], always("bar".to_owned()).map(|x| Some(RefFn::new(x, |x| x.as_str()))))
|
||||
|
||||
;
|
||||
}
|
||||
|
|
196
src/traits.rs
196
src/traits.rs
|
@ -1,7 +1,4 @@
|
|||
use dom_operations;
|
||||
use dom::DerefFn;
|
||||
use std::ops::Deref;
|
||||
use stdweb::Reference;
|
||||
use dom::RefFn;
|
||||
|
||||
pub use animation::AnimatedSignalVec;
|
||||
|
||||
|
@ -18,129 +15,116 @@ impl<A, F> Mixin<A> for F where F: FnOnce(A) -> A {
|
|||
}
|
||||
|
||||
|
||||
pub trait StyleName {
|
||||
fn set_style<A: AsRef<Reference>>(&self, element: &A, value: &str, important: bool);
|
||||
fn remove_style<A: AsRef<Reference>>(&self, element: &A);
|
||||
}
|
||||
|
||||
impl<'a> StyleName for &'a str {
|
||||
#[inline]
|
||||
fn set_style<A: AsRef<Reference>>(&self, element: &A, value: &str, important: bool) {
|
||||
if !dom_operations::try_set_style(element, self, value, important) {
|
||||
panic!("style is incorrect:\n name: {}\n value: {}", self, value);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remove_style<A: AsRef<Reference>>(&self, element: &A) {
|
||||
dom_operations::remove_style(element, self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! array_style_name {
|
||||
($size:expr) => {
|
||||
impl<'a> StyleName for [&'a str; $size] {
|
||||
#[inline]
|
||||
fn set_style<A: AsRef<Reference>>(&self, element: &A, value: &str, important: bool) {
|
||||
let mut okay = false;
|
||||
|
||||
for name in self.iter() {
|
||||
if dom_operations::try_set_style(element, name, value, important) {
|
||||
okay = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !okay {
|
||||
panic!("style is incorrect:\n names: {}\n value: {}", self.join(", "), value);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remove_style<A: AsRef<Reference>>(&self, element: &A) {
|
||||
for name in self.iter() {
|
||||
dom_operations::remove_style(element, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! array_style_names {
|
||||
($($size:expr),*) => {
|
||||
$(array_style_name!($size);)*
|
||||
};
|
||||
}
|
||||
|
||||
array_style_names!(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);
|
||||
|
||||
|
||||
// TODO figure out a way to implement this for all of AsRef / Borrow / etc.
|
||||
// TODO implementations for &String and &mut String
|
||||
pub trait IntoStr {
|
||||
type Output: Deref<Target = str>;
|
||||
|
||||
fn into_str(self) -> Self::Output;
|
||||
pub trait AsStr {
|
||||
fn as_str(&self) -> &str;
|
||||
}
|
||||
|
||||
impl IntoStr for String {
|
||||
type Output = Self;
|
||||
|
||||
impl AsStr for String {
|
||||
#[inline]
|
||||
fn into_str(self) -> Self::Output {
|
||||
fn as_str(&self) -> &str {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoStr for &'a str {
|
||||
type Output = Self;
|
||||
|
||||
impl<'a> AsStr for &'a str {
|
||||
#[inline]
|
||||
fn into_str(self) -> Self::Output {
|
||||
fn as_str(&self) -> &str {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoStr for &'a mut str {
|
||||
type Output = Self;
|
||||
|
||||
impl<'a> AsStr for &'a mut str {
|
||||
#[inline]
|
||||
fn into_str(self) -> Self::Output {
|
||||
fn as_str(&self) -> &str {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> IntoStr for DerefFn<A, B> where B: Fn(&A) -> &str {
|
||||
type Output = Self;
|
||||
impl<A, C> AsStr for RefFn<A, str, C> where C: Fn(&A) -> &str {
|
||||
#[inline]
|
||||
fn as_str(&self) -> &str {
|
||||
self.call_ref()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait MultiStr {
|
||||
fn any<F>(&self, f: F) -> bool where F: FnMut(&str) -> bool;
|
||||
|
||||
#[inline]
|
||||
fn into_str(self) -> Self::Output {
|
||||
fn each<F>(&self, mut f: F) where F: FnMut(&str) {
|
||||
self.any(|x| {
|
||||
f(x);
|
||||
false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> MultiStr for A where A: AsStr {
|
||||
#[inline]
|
||||
fn any<F>(&self, mut f: F) -> bool where F: FnMut(&str) -> bool {
|
||||
f(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO it would be great to use IntoIterator instead, and then we can replace the array implementations with it
|
||||
/*impl<'a, A> MultiStr for &'a [A] where A: AsStr {
|
||||
#[inline]
|
||||
fn any<F>(&self, mut f: F) -> bool where F: FnMut(&str) -> bool {
|
||||
self.iter().any(|x| f(x.as_str()))
|
||||
}
|
||||
}*/
|
||||
|
||||
// TODO it would be great to use IntoIterator or Iterator instead
|
||||
/*impl<'a, A, C> MultiStr for RefFn<A, [&'a str], C> where C: Fn(&A) -> &[&'a str] {
|
||||
#[inline]
|
||||
fn any<F>(&self, mut f: F) -> bool where F: FnMut(&str) -> bool {
|
||||
self.call_ref().iter().any(|x| f(x))
|
||||
}
|
||||
}*/
|
||||
|
||||
macro_rules! array_multi_str {
|
||||
($size:expr) => {
|
||||
impl<A> MultiStr for [A; $size] where A: AsStr {
|
||||
#[inline]
|
||||
fn any<F>(&self, mut f: F) -> bool where F: FnMut(&str) -> bool {
|
||||
self.iter().any(|x| f(x.as_str()))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! array_multi_strs {
|
||||
($($size:expr),*) => {
|
||||
$(array_multi_str!($size);)*
|
||||
};
|
||||
}
|
||||
|
||||
array_multi_strs!(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);
|
||||
|
||||
|
||||
pub trait OptionStr {
|
||||
type Output;
|
||||
|
||||
fn into_option(self) -> Option<Self::Output>;
|
||||
}
|
||||
|
||||
impl<A> OptionStr for A where A: MultiStr {
|
||||
type Output = A;
|
||||
|
||||
#[inline]
|
||||
fn into_option(self) -> Option<A> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> OptionStr for Option<A> where A: MultiStr {
|
||||
type Output = A;
|
||||
|
||||
#[inline]
|
||||
fn into_option(self) -> Option<A> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO figure out a way to implement this for all of AsRef / Borrow / etc.
|
||||
pub trait IntoOptionStr {
|
||||
type Output: Deref<Target = str>;
|
||||
|
||||
fn into_option_str(self) -> Option<Self::Output>;
|
||||
}
|
||||
|
||||
impl<A: IntoStr> IntoOptionStr for A {
|
||||
type Output = A::Output;
|
||||
|
||||
#[inline]
|
||||
fn into_option_str(self) -> Option<Self::Output> {
|
||||
Some(self.into_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: IntoStr> IntoOptionStr for Option<A> {
|
||||
type Output = A::Output;
|
||||
|
||||
#[inline]
|
||||
fn into_option_str(self) -> Option<Self::Output> {
|
||||
self.map(|x| x.into_str())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue