1
  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
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#![recursion_limit = "256"]
extern crate yew;
#[macro_use]
extern crate stdweb;

use stdweb::web::Node;
use yew::prelude::*;

/// SVG icon Properties
///
/// # example
/// ```rust
///
///
/// ```
#[derive(PartialEq, Clone)]
pub struct SvgProps {
    pub href: String,
    pub content: String,
    pub class: String,
    pub style: String,
    pub width: String,
    pub height: String,
    pub view_box: String,
}

impl Default for SvgProps {
    fn default() -> Self {
        SvgProps {
            href: Default::default(),
            content: Default::default(),
            class: Default::default(),
            style: Default::default(),
            width: Default::default(),
            height: Default::default(),
            view_box: Default::default(),
        }
    }
}

pub struct SVG {
    props: SvgProps,
}

impl<U> Renderable<U> for SVG
    where
        U: Component
{
    fn view(&self) -> Html<U> {
        use stdweb::unstable::TryFrom;
        let mut html = String::new();
        let props = &self.props;
        if !props.href.is_empty() {
            html += "<svg";
            if !props.class.is_empty() {
                html += &format!(" class={}", props.class);
            }
            if !props.style.is_empty() {
                html += &format!(" style={}", props.style);
            }
            if !props.view_box.is_empty() {
                html += &format!(" viewBox={}", props.view_box);
            }
            if !props.width.is_empty() {
                html += &format!(" width={}", props.width);
            }
            if !props.height.is_empty() {
                html += &format!(" height={}", props.height);
            }
            html += &format!(r#"><use xlink:href="{}"></use></svg>"#, props.href);
        } else if !props.content.is_empty() {
            html = props.content.clone();
        }
        let js_svg = js! {
            var div = document.createElement("div");
            div.innerHTML = @{html};
            var es = div.getElementsByTagName("svg");
            for (var i = 0; i < es.length; i++) {
                if @{!props.class.is_empty()} {
                    es[i].setAttribute("class", @{&props.class});
                }
                if @{!props.style.is_empty()} {
                    es[i].setAttribute("style", @{&props.style});
                }
                if @{!props.width.is_empty()} {
                    es[i].setAttribute("width", @{&props.width});
                }
                if @{!props.height.is_empty()} {
                    es[i].setAttribute("height", @{&props.height});
                }
                if @{!props.view_box.is_empty()} {
                    es[i].setAttribute("viewBox", @{&props.view_box});
                }
            }
            return div;
        };
        let node = Node::try_from(js_svg).expect("convert js_svg");
        let vnode = yew::virtual_dom::VNode::VRef(node);
        vnode
    }
}

pub enum Msg {
    SetHref(String),
    SetContent(String),
    SetWidth(String),
    SetHeight(String),
    SetClass(String),
    SetStyle(String),
    SetViewBox(String),
}

impl Component for SVG {
    type Message = Msg;
    type Properties = SvgProps;

    fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
        SVG {
            props,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        use Msg::*;
        match msg {
            SetHref(v) => {
                self.props.content = Default::default();
                self.props.href = v
            }
            SetContent(v) => {
                self.props.href = Default::default();
                self.props.content = v;
            }
            SetWidth(v) => self.props.width = v,
            SetHeight(v) => self.props.height = v,
            SetClass(v) => self.props.class = v,
            SetStyle(v) => self.props.style = v,
            SetViewBox(v) => self.props.view_box = v,
        }
        true
    }

    fn change(&mut self, props: Self::Properties) -> ShouldRender {
        let changed = self.props != props;
        self.props = props;
        changed
    }
}