Skip to content

Commit 2d758cb

Browse files
committed
✨ Use data attribute to specify custom trigger
1 parent 2956a68 commit 2d758cb

File tree

4 files changed

+131
-90
lines changed

4 files changed

+131
-90
lines changed

dist/feedback-js.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/index.html

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
</head>
1616

1717
<body>
18+
<h1>feedback-js Example</h1>
19+
<p>This is an example to show how <a href="https://github.com/BetaHuhn/feedback-js">feedback-js</a> works.</p>
20+
<p>To trigger the widget, click <a href="#" data-feedback-trigger>here</a> or the button in the bottom right corner.</p>
1821
</body>
1922

20-
<script src="../dist/feedback-js.min.js" data-feedback-opts='{ "id": "test", "endpoint": "http://172.21.52.196:6600/form/feedback", "emailField": true }'></script>
23+
<script src="../dist/feedback-js.min.js" data-feedback-opts='{ "id": "test", "endpoint": "http://172.21.52.196:6600/form/feedback", "emailField": true, "forceShowButton": true }'></script>
2124
</html>

src/feedback.js

+106-85
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default class Feedback {
1616
endpoint: '',
1717
events: false,
1818
emailField: false,
19+
forceShowButton: false,
1920
btnTitle: 'Feedback',
2021
title: 'Feedback',
2122
contactText: 'Want to chat?',
@@ -53,9 +54,32 @@ export default class Feedback {
5354

5455
}
5556

56-
_renderButton() {
57+
/**
58+
* Attach feedback styles and button to current page
59+
* @param {boolean} renderButton Render the default button
60+
*/
61+
attach(renderButton = true) {
62+
const div = document.createElement('div')
63+
div.id = 'feedback-root'
64+
document.body.insertBefore(div, document.body.firstChild)
65+
66+
const comment = document.createComment('feedback-js modal code')
67+
document.body.insertBefore(comment, document.body.firstChild)
68+
69+
this.root = div
70+
71+
this._addStyle()
72+
73+
if (renderButton || this.options.forceShowButton) {
74+
this.renderButton()
75+
}
76+
}
77+
78+
renderButton() {
5779
if (!this.root) return
5880

81+
this.showDefaultBtn = true
82+
5983
const html = `
6084
<div class="feedback-btn-wrapper">
6185
<button id="feedback-btn" title="Give feedback">
@@ -69,11 +93,11 @@ export default class Feedback {
6993

7094
const button = document.getElementById('feedback-btn')
7195
button.addEventListener('click', () => {
72-
this._renderView()
96+
this.renderModal()
7397
})
7498
}
7599

76-
_renderView() {
100+
renderModal() {
77101
if (!this.root) return
78102

79103
const html = `
@@ -102,26 +126,36 @@ export default class Feedback {
102126

103127
const button = document.getElementById('feedback-close')
104128
button.addEventListener('click', () => {
105-
this._renderButton()
129+
this.closeModal()
106130
})
107131

108-
Object.entries(this.options.types).forEach(([ id, item ]) => {
132+
Object.keys(this.options.types).forEach((id) => {
109133
const elem = document.getElementById(`feedback-item-${ id }`)
110134

111135
elem.onclick = () => {
112-
this._renderForm(id, `${ item.icon } ${ item.text }`)
136+
this.renderForm(id)
113137
}
114138
})
115139
}
116140

117-
_renderForm(type, title) {
141+
closeModal() {
142+
this.root.innerHTML = ''
143+
144+
if (this.showDefaultBtn) {
145+
this.renderButton()
146+
}
147+
}
148+
149+
renderForm(type) {
118150
if (!this.root) return
119151

152+
const feedbackType = this.options.types[type]
153+
120154
const html = `
121155
<div class="feedback-wrapper">
122156
<div class="feedback-main">
123157
<div class="feedback-header">
124-
<p>${ title }</p>
158+
<p>${ feedbackType.icon } ${ feedbackType.text }</p>
125159
</div>
126160
<div class="feedback-content">
127161
${ this.options.emailField ? '<input id="feedback-email" type="email" name="email" placeholder="Email address (optional)">' : '' }
@@ -147,36 +181,78 @@ export default class Feedback {
147181

148182
const button = document.getElementById('feedback-close')
149183
button.addEventListener('click', () => {
150-
this._renderButton()
184+
this.closeModal()
151185
})
152186

153187
const back = document.getElementById('feedback-back')
154188
back.addEventListener('click', () => {
155-
this._renderView()
189+
this.renderModal()
156190
})
157191

158192
const submit = document.getElementById('feedback-submit')
159193
submit.addEventListener('click', () => {
160-
const message = document.getElementById('feedback-message').value
161-
const email = this.options.emailField ? document.getElementById('feedback-email').value : undefined
194+
this.submitForm()
195+
})
196+
}
162197

163-
const data = {
164-
id: this.options.id,
165-
email: email,
166-
feedbackType: this.current,
167-
url: window.location.href,
168-
message: message
169-
}
198+
submitForm() {
199+
const message = document.getElementById('feedback-message').value
200+
const email = this.options.emailField ? document.getElementById('feedback-email').value : undefined
170201

171-
if (this.options.events) {
172-
const event = new CustomEvent('feedback-submit', { detail: data })
173-
window.dispatchEvent(event)
174-
this._renderSuccess()
175-
return
176-
}
202+
const data = {
203+
id: this.options.id,
204+
email: email,
205+
feedbackType: this.current,
206+
url: window.location.href,
207+
message: message
208+
}
177209

178-
this.send(data.feedbackType, data.message, data.url, data.email)
179-
})
210+
if (this.options.events) {
211+
const event = new CustomEvent('feedback-submit', { detail: data })
212+
window.dispatchEvent(event)
213+
this._renderSuccess()
214+
return
215+
}
216+
217+
this.sendToEndpoint(data.feedbackType, data.message, data.url, data.email)
218+
}
219+
220+
/**
221+
* Send feedback to backend
222+
* @param {string} feedbackType - type of feedback
223+
* @param {string} message - the actual feedback message
224+
* @param {string} [url] - url/page the feedback was collected on
225+
* @param {string} [email] - email of user optional
226+
*/
227+
sendToEndpoint(feedbackType, message, url, email) {
228+
if (!feedbackType || !message) {
229+
if (!this.root) throw new Error('missing parameters')
230+
return
231+
}
232+
233+
const parsedData = {
234+
id: this.options.id,
235+
email: email,
236+
feedbackType: feedbackType,
237+
url: url,
238+
message: message
239+
}
240+
241+
this._renderLoading()
242+
243+
const request = new XMLHttpRequest()
244+
request.open('POST', this.options.endpoint)
245+
request.setRequestHeader('Content-type', 'application/json')
246+
request.send(JSON.stringify(parsedData))
247+
request.onreadystatechange = () => {
248+
if (request.readyState === 4) {
249+
if (request.status === 200) {
250+
return this._renderSuccess()
251+
}
252+
253+
this._renderFailed()
254+
}
255+
}
180256
}
181257

182258
_renderLoading() {
@@ -190,7 +266,7 @@ export default class Feedback {
190266

191267
const button = document.getElementById('feedback-close')
192268
button.addEventListener('click', () => {
193-
this._renderButton()
269+
this.closeModal()
194270
})
195271
}
196272

@@ -208,7 +284,7 @@ export default class Feedback {
208284
this.root.innerHTML = html
209285

210286
setTimeout(() => {
211-
this._renderButton()
287+
this.renderButton()
212288
}, 3000)
213289
}
214290

@@ -237,65 +313,10 @@ export default class Feedback {
237313

238314
const button = document.getElementById('feedback-close')
239315
button.addEventListener('click', () => {
240-
this._renderButton()
316+
this.closeModal()
241317
})
242318
}
243319

244-
/**
245-
* Send feedback to backend
246-
* @param {string} feedbackType - type of feedback
247-
* @param {string} message - the actual feedback message
248-
* @param {string} [url] - url/page the feedback was collected on
249-
* @param {string} [email] - email of user optional
250-
*/
251-
send(feedbackType, message, url, email) {
252-
if (!feedbackType || !message) {
253-
if (!this.root) throw new Error('missing parameters')
254-
return
255-
}
256-
257-
const parsedData = {
258-
id: this.options.id,
259-
email: email,
260-
feedbackType: feedbackType,
261-
url: url,
262-
message: message
263-
}
264-
265-
this._renderLoading()
266-
267-
const request = new XMLHttpRequest()
268-
request.open('POST', this.options.endpoint)
269-
request.setRequestHeader('Content-type', 'application/json')
270-
request.send(JSON.stringify(parsedData))
271-
request.onreadystatechange = () => {
272-
if (request.readyState === 4) {
273-
if (request.status === 200) {
274-
return this._renderSuccess()
275-
}
276-
277-
this._renderFailed()
278-
}
279-
}
280-
}
281-
282-
/**
283-
* Attach feedback button to current page
284-
*/
285-
attach() {
286-
const div = document.createElement('div')
287-
div.id = 'feedback-root'
288-
document.body.insertBefore(div, document.body.firstChild)
289-
290-
const comment = document.createComment('feedback-js modal code')
291-
document.body.insertBefore(comment, document.body.firstChild)
292-
293-
this.root = div
294-
295-
this._addStyle()
296-
this._renderButton()
297-
}
298-
299320
_addStyle() {
300321
const css = `
301322
#feedback-root{

src/index.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ export default Feedback
33

44
const detect = () => {
55
const optsElem = document.querySelector('[data-feedback-opts]')
6+
const buttonElems = document.querySelectorAll('[data-feedback-trigger]')
67

78
// If no attributes are found, assume programmatic usage and attach Feedback class to window
8-
if (!optsElem) {
9+
if (!optsElem && buttonElems.length < 1) {
910
window.Feedback = Feedback
1011

1112
return
@@ -18,8 +19,24 @@ const detect = () => {
1819
window.addEventListener('load', () => {
1920
window.feedback = new Feedback(options)
2021

21-
// Attach the feedback button to the page
22-
window.feedback.attach()
22+
const renderDefaultButton = buttonElems.length < 1
23+
24+
// Initalize the feedback widget
25+
window.feedback.attach(renderDefaultButton)
26+
27+
// Attach event listeners to data-drkmd-toggle elements
28+
if (!renderDefaultButton) {
29+
buttonElems.forEach((item) => {
30+
item.addEventListener('click', () => {
31+
window.feedback.renderModal()
32+
})
33+
})
34+
35+
return
36+
}
37+
38+
// Render default button
39+
window.feedback.renderButton()
2340
})
2441
}
2542

0 commit comments

Comments
 (0)