UNPKG

4.73 kBJavaScriptView Raw
1
2import {getSvgIcon, createSvgUse, changeSvgIcon} from "./utils/svg";
3
4/**
5 * SVG Spinner Component
6 *
7 * Creates inline <svg class="{className}"><use xlink:href="#{icon}"></svg>
8 * and appends it to any 'element'
9 *
10 * Use Spinner.toggle(element) to add/remove spinner
11 *
12 * If `element` itself is an inline <svg>,
13 * then saves original icon ID
14 * and changes only xlink:href attribute
15 * instead of creating and appending new one <svg>
16 * Useful, for example, when search icon temporary could be replaced with spinner
17 */
18
19export const SpinnerConfig = {
20
21 icon: 'spinner',
22 className: 'i-spinner', // class name with rotate animation since SVG SMIL is deprecated and is not working in IE/Edge
23
24 tagNameFade: 'fade',
25 classNameFade: null,
26 classNameFadeShow: 'show',
27 animationDuration: 600
28
29};
30
31export const Spinner = {
32
33 Config: SpinnerConfig,
34
35 insertSpinner(element, spinner) {
36 element.appendChild(spinner);
37 },
38
39 removeSpinner(element, spinner) {
40 element.removeChild(spinner);
41 },
42
43 getSpinner(element) {
44 return element.__bunny_spinner || false;
45 },
46
47 has(element) {
48 return element.__bunny_spinner !== undefined;
49 },
50
51 show(element, removeText = false) {
52 if (element.tagName === 'SVG' || element.tagName === 'svg') {
53 element.__bunny_spinner = getSvgIcon(element);
54 changeSvgIcon(element, this.Config.icon);
55 element.classList.add(this.Config.className);
56 } else {
57 if (removeText) {
58 element.__bunny_spinner_text = element.innerHTML;
59 element.textContent = '';
60 }
61 element.__bunny_spinner = createSvgUse(this.Config.icon, {class: this.Config.className});
62 this.insertSpinner(element, element.__bunny_spinner);
63 }
64 },
65
66 hide(element, removeText = false) {
67 if (element.tagName === 'SVG' || element.tagName === 'svg') {
68 element.classList.remove(this.Config.className);
69 changeSvgIcon(element, element.__bunny_spinner);
70 } else {
71 this.removeSpinner(element, element.__bunny_spinner);
72 if (removeText) {
73 element.innerHTML = element.__bunny_spinner_text;
74 delete element.__bunny_spinner_text;
75 }
76 }
77 delete element.__bunny_spinner;
78 },
79
80 toggle(element, removeText = false) {
81 if (this.has(element)) {
82 this.hide(element, removeText);
83 return true;
84 } else {
85 this.show(element, removeText);
86 return false;
87 }
88 },
89
90 fadePage(text = null, textClass = null) {
91 return new Promise(resolve => {
92 const fade = this.getFade();
93 if (!fade) {
94 const el = document.createElement(this.Config.tagNameFade);
95 if (this.Config.classNameFade !== null) {
96 el.classList.add(this.Config.classNameFade);
97 }
98 const textNode = document.createElement('div');
99 textNode.classList.add('fade');
100 if (textClass) {
101 textNode.classList.add(textClass);
102 }
103 el.appendChild(textNode);
104 document.body.appendChild(el);
105 setTimeout(() => {
106 if (text !== null) {
107 textNode.textContent = text;
108 textNode.classList.add('in');
109 }
110 this.toggle(el);
111 el.classList.add(this.Config.classNameFadeShow);
112 setTimeout(() => {
113 resolve();
114 }, this.Config.animationDuration);
115 }, 0);
116 } else {
117 resolve();
118 }
119 });
120 },
121
122 getFade() {
123 return document.getElementsByTagName(this.Config.tagNameFade)[0] || false;
124 },
125
126 getFadeIcon() {
127 return this.getSpinner(this.getFade());
128 },
129
130 getFadeText() {
131 return this.getFade().getElementsByTagName('div')[0];
132 },
133
134 unfadePage() {
135 return new Promise(resolve => {
136 const fade = this.getFade();
137 if (fade) {
138 fade.classList.remove(this.Config.classNameFadeShow);
139 setTimeout(() => {
140 document.body.removeChild(fade);
141 resolve();
142 }, this.Config.animationDuration);
143 } else {
144 resolve();
145 }
146 });
147 },
148
149 setFadeIcon(newIconId, className = null) {
150 const spinner = this.getFadeIcon();
151 spinner.classList.remove(this.Config.className);
152 changeSvgIcon(spinner, newIconId);
153 if (className) {
154 spinner.classList.add(className);
155 }
156 },
157
158 setFadeText(newText, newClassAttribute = null) {
159 const text = this.getFadeText();
160 text.classList.remove('in');
161 setTimeout(() => {
162 text.textContent = newText;
163 if (newClassAttribute) {
164 text.setAttribute('class', newClassAttribute);
165 }
166 text.classList.add('in');
167 }, 300);
168 }
169
170};