Skip to content
This repository was archived by the owner on Oct 1, 2024. It is now read-only.

Commit 2105f6e

Browse files
author
george
committed
make dom api expressive with attribute manipulation - get, set, remove become new methods. handling all three is cryptical and difficult to reason about
1 parent 6f5a585 commit 2105f6e

File tree

7 files changed

+72
-74
lines changed

7 files changed

+72
-74
lines changed

.eslintrc.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ module.exports = {
198198
"no-var": ERROR,
199199
"object-shorthand": [ERROR, ALWAYS],
200200
"prefer-const": ERROR,
201-
"prefer-spread": ERROR,
202201
"prefer-template": ERROR,
203202
"require-yield": ERROR,
204203

src/js/__tests__/utils.spec.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import ContextUtil, { browserEnv, dom, getFocusableElements, iOSMobile } from "../utils"
2+
3+
describe("browserEnv", () => {})
4+
describe("dom", () => {})
5+
describe("getFocusableElements", () => {})
6+
describe("iOSMobile", () => {})
7+
describe("ContextUtil", () => {})

src/js/accordion.js

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ export default class Accordion {
8888
// private
8989

9090
_setup(instance) {
91-
const buttonTargetId = dom.attr(instance, Selectors.DATA_TARGET)
92-
const accordionId = dom.attr(instance, Selectors.DATA_PARENT)
91+
const buttonTargetId = dom.getAttr(instance, Selectors.DATA_TARGET)
92+
const accordionId = dom.getAttr(instance, Selectors.DATA_PARENT)
9393
const buttonContent = dom.find(`#${buttonTargetId}`)
9494

9595
if (!accordionId) {
@@ -115,29 +115,29 @@ export default class Accordion {
115115

116116
const buttonContentChildren = getFocusableElements(`#${buttonContent.id}`)
117117

118-
dom.attr(instance, Selectors.ARIA_CONTROLS, buttonTargetId)
119-
dom.attr(buttonContent, Selectors.ARIA_LABELLEDBY, buttonId)
118+
dom.setAttr(instance, Selectors.ARIA_CONTROLS, buttonTargetId)
119+
dom.setAttr(buttonContent, Selectors.ARIA_LABELLEDBY, buttonId)
120120

121-
const contentShouldExpand = dom.attr(accordionRow, Selectors.DATA_VISIBLE)
121+
const contentShouldExpand = dom.getAttr(accordionRow, Selectors.DATA_VISIBLE)
122122

123123
if (!contentShouldExpand) {
124124
throw new Error(Messages.NO_VISIBLE_ERROR(buttonTargetId))
125125
}
126126

127127
if (contentShouldExpand === "true") {
128128
dom.css(buttonContent, "maxHeight", `${buttonContent.scrollHeight}px`)
129-
dom.attr(instance, Selectors.ARIA_EXPANDED, "true")
130-
dom.attr(buttonContent, Selectors.ARIA_HIDDEN, "false")
129+
dom.setAttr(instance, Selectors.ARIA_EXPANDED, "true")
130+
dom.setAttr(buttonContent, Selectors.ARIA_HIDDEN, "false")
131131

132132
buttonContentChildren.forEach(element => {
133-
dom.attr(element, Selectors.TABINDEX, "0")
133+
dom.setAttr(element, Selectors.TABINDEX, "0")
134134
})
135135
} else {
136-
dom.attr(instance, Selectors.ARIA_EXPANDED, "false")
137-
dom.attr(buttonContent, Selectors.ARIA_HIDDEN, "true")
136+
dom.setAttr(instance, Selectors.ARIA_EXPANDED, "false")
137+
dom.setAttr(buttonContent, Selectors.ARIA_HIDDEN, "true")
138138

139139
buttonContentChildren.forEach(element => {
140-
dom.attr(element, Selectors.TABINDEX, "-1")
140+
dom.setAttr(element, Selectors.TABINDEX, "-1")
141141
})
142142
}
143143
}
@@ -170,14 +170,14 @@ export default class Accordion {
170170
}
171171

172172
_setVisibleState() {
173-
const accordionButtonState = dom.attr(this._activeRow, Selectors.DATA_VISIBLE)
173+
const accordionButtonState = dom.getAttr(this._activeRow, Selectors.DATA_VISIBLE)
174174
this._nextButtonExpandState = accordionButtonState === "true" ? "false" : "true"
175175
this._nextContentHiddenState = this._nextButtonExpandState === "false" ? "true" : "false"
176176
}
177177

178178
_setIds() {
179-
this._activeContainerId = dom.attr(this._activeButton, Selectors.DATA_PARENT)
180-
this._activeAccordionRowId = dom.attr(this._activeButton, Selectors.DATA_TARGET)
179+
this._activeContainerId = dom.getAttr(this._activeButton, Selectors.DATA_PARENT)
180+
this._activeAccordionRowId = dom.getAttr(this._activeButton, Selectors.DATA_TARGET)
181181
}
182182

183183
_setActiveContainer() {
@@ -223,13 +223,13 @@ export default class Accordion {
223223
}
224224

225225
_toggleSelectedAccordion() {
226-
dom.attr(this._activeRow, Selectors.DATA_VISIBLE, this._nextButtonExpandState)
227-
dom.attr(this._activeButton, Selectors.ARIA_EXPANDED, this._nextButtonExpandState)
228-
dom.attr(this._activeContent, Selectors.ARIA_HIDDEN, this._nextContentHiddenState)
226+
dom.setAttr(this._activeRow, Selectors.DATA_VISIBLE, this._nextButtonExpandState)
227+
dom.setAttr(this._activeButton, Selectors.ARIA_EXPANDED, this._nextButtonExpandState)
228+
dom.setAttr(this._activeContent, Selectors.ARIA_HIDDEN, this._nextContentHiddenState)
229229

230230
getFocusableElements(`#${this._activeAccordionRowId}`).forEach(element => {
231231
const value = this._nextButtonExpandState === "true" ? "0" : "-1"
232-
dom.attr(element, Selectors.TABINDEX, value)
232+
dom.setAttr(element, Selectors.TABINDEX, value)
233233
})
234234

235235
if (dom.css(this._activeContent, "maxHeight")) {
@@ -239,7 +239,7 @@ export default class Accordion {
239239
}
240240
}
241241

242-
_toggleAttributeInCollection(elements, attributeName, newValue) {
243-
elements.forEach(element => dom.attr(element, attributeName, newValue))
242+
_toggleAttributeInCollection(elements, attributeName, value) {
243+
elements.forEach(element => dom.setAttr(element, attributeName, value))
244244
}
245245
}

src/js/dropdown.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export default class Dropdown {
114114
const dropdownAttr = `[${Selectors.DATA_DROPDOWN}="${dropdownId}"]`
115115
const dropdownButton = dom.find(`${dropdownAttr} > ${this._dropdownTargetAttr}`)
116116

117-
if (!dom.attr(dropdownButton, Selectors.DATA_PARENT)) {
117+
if (!dom.getAttr(dropdownButton, Selectors.DATA_PARENT)) {
118118
throw new Error(Messages.NO_PARENT_ERROR)
119119
}
120120

@@ -124,11 +124,11 @@ export default class Dropdown {
124124
throw new Error(Messages.NO_MENU_ERROR(dropdownAttr))
125125
}
126126

127-
dom.attr(dropdownMenu, Selectors.ARIA_LABELLEDBY, dropdownButton.id)
127+
dom.setAttr(dropdownMenu, Selectors.ARIA_LABELLEDBY, dropdownButton.id)
128128

129-
dom.attr(dropdownButton, Selectors.ARIA_CONTROLS, dropdownMenu.id)
130-
dom.attr(dropdownButton, Selectors.ARIA_HASPOPUP, "true")
131-
dom.attr(dropdownButton, Selectors.ARIA_EXPANDED, "false")
129+
dom.setAttr(dropdownButton, Selectors.ARIA_CONTROLS, dropdownMenu.id)
130+
dom.setAttr(dropdownButton, Selectors.ARIA_HASPOPUP, "true")
131+
dom.setAttr(dropdownButton, Selectors.ARIA_EXPANDED, "false")
132132

133133
const dropdownMenuItemsAttr = `${dropdownAttr} > ul > li`
134134
const dropdownMenuListItems = dom.findAll(dropdownMenuItemsAttr)
@@ -137,7 +137,7 @@ export default class Dropdown {
137137
throw new Error(Messages.NO_DROPDOWN_ITEMS_ERROR(dropdownAttr))
138138
}
139139

140-
dropdownMenuListItems.forEach(item => dom.attr(item, Selectors.ROLE, "none"))
140+
dropdownMenuListItems.forEach(item => dom.setAttr(item, Selectors.ROLE, "none"))
141141

142142
const dropdownMenuButtons = this._getDropdownLinks(dropdownAttr)
143143

@@ -146,8 +146,8 @@ export default class Dropdown {
146146
}
147147

148148
dropdownMenuButtons.forEach(link => {
149-
dom.attr(link, Selectors.ROLE, "menuitem")
150-
dom.attr(link, Selectors.TABINDEX, "-1")
149+
dom.setAttr(link, Selectors.ROLE, "menuitem")
150+
dom.setAttr(link, Selectors.TABINDEX, "-1")
151151
})
152152
}
153153

@@ -200,11 +200,11 @@ export default class Dropdown {
200200
}
201201

202202
_handleHideState() {
203-
dom.attr(this._activeDropdownButton, Selectors.ARIA_EXPANDED, "false")
204-
dom.attr(this._activeDropdown, Selectors.DATA_VISIBLE, "false")
203+
dom.setAttr(this._activeDropdownButton, Selectors.ARIA_EXPANDED, "false")
204+
dom.setAttr(this._activeDropdown, Selectors.DATA_VISIBLE, "false")
205205

206206
this._activeDropdownLinks.forEach(link => {
207-
dom.attr(link, Selectors.TABINDEX, "-1")
207+
dom.setAttr(link, Selectors.TABINDEX, "-1")
208208
link.removeEventListener(Events.CLICK, this._handleClose)
209209
})
210210
}
@@ -215,7 +215,7 @@ export default class Dropdown {
215215
}
216216

217217
_setActiveDropdownId() {
218-
this._activeDropdownId = dom.attr(this._activeDropdownButton, Selectors.DATA_PARENT)
218+
this._activeDropdownId = dom.getAttr(this._activeDropdownButton, Selectors.DATA_PARENT)
219219
}
220220

221221
_startEvents() {
@@ -231,7 +231,7 @@ export default class Dropdown {
231231
this._lastDropdownLink.addEventListener(Events.KEYDOWN, this._handleLastTabClose)
232232

233233
this._activeDropdownLinks.forEach(link => {
234-
dom.attr(link, Selectors.TABINDEX, "0")
234+
dom.setAttr(link, Selectors.TABINDEX, "0")
235235
link.addEventListener(Events.CLICK, this._handleClose)
236236
})
237237

@@ -244,12 +244,12 @@ export default class Dropdown {
244244
}
245245

246246
_setVisibleState() {
247-
dom.attr(this._activeDropdownButton, Selectors.ARIA_EXPANDED, "true")
248-
dom.attr(this._activeDropdown, Selectors.DATA_VISIBLE, "true")
247+
dom.setAttr(this._activeDropdownButton, Selectors.ARIA_EXPANDED, "true")
248+
dom.setAttr(this._activeDropdown, Selectors.DATA_VISIBLE, "true")
249249
}
250250

251251
_setActiveDropdownMenu() {
252-
this._activeDropdownMenuId = dom.attr(this._activeDropdownButton, Selectors.DATA_TARGET)
252+
this._activeDropdownMenuId = dom.getAttr(this._activeDropdownButton, Selectors.DATA_TARGET)
253253
this._activeDropdownMenu = dom.find(`#${this._activeDropdownMenuId}`)
254254
}
255255

@@ -303,9 +303,9 @@ export default class Dropdown {
303303
}
304304

305305
_handleReturnFocus() {
306-
dom.attr(this._activeDropdownButton, Selectors.TAB_INDEX, "-1")
306+
dom.setAttr(this._activeDropdownButton, Selectors.TAB_INDEX, "-1")
307307
this._activeDropdownButton.focus()
308-
dom.attr(this._activeDropdownButton, Selectors.TAB_INDEX, false)
308+
dom.removeAttr(this._activeDropdownButton, Selectors.TAB_INDEX)
309309
}
310310

311311
_getDropdownLinks(attr) {

src/js/modal.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export default class Modal {
7171
this._modals = dom.findAll(this._modalContainerAttr)
7272

7373
getFocusableElements(this._modalContainerAttr).forEach(element => {
74-
dom.attr(element, Selectors.TABINDEX, "-1")
74+
dom.setAttr(element, Selectors.TABINDEX, "-1")
7575
})
7676

7777
if (this._modals.length) {
@@ -85,7 +85,7 @@ export default class Modal {
8585
if (!browserEnv) return
8686

8787
this._modals.forEach(instance => {
88-
const id = dom.attr(instance, Selectors.DATA_MODAL)
88+
const id = dom.getAttr(instance, Selectors.DATA_MODAL)
8989
const button = dom.find(`[${Selectors.DATA_TARGET}='${id}']`)
9090

9191
if (!button) {
@@ -99,7 +99,7 @@ export default class Modal {
9999
// private
100100

101101
_setup(instance) {
102-
const modalId = dom.attr(instance, Selectors.DATA_MODAL)
102+
const modalId = dom.getAttr(instance, Selectors.DATA_MODAL)
103103

104104
if (!modalId) {
105105
throw new Error(Messages.NO_MODAL_ID_ERROR)
@@ -113,10 +113,10 @@ export default class Modal {
113113

114114
const modalWrapper = dom.find(`[${Selectors.DATA_MODAL}='${modalId}']`)
115115

116-
dom.attr(modalWrapper, Selectors.ARIA_HIDDEN, "true")
117-
dom.attr(modalWrapper, Selectors.DATA_VISIBLE, "false")
118-
dom.attr(modal, Selectors.ARIA_MODAL, "true")
119-
dom.attr(modal, Selectors.ROLE, "dialog")
116+
dom.setAttr(modalWrapper, Selectors.ARIA_HIDDEN, "true")
117+
dom.setAttr(modalWrapper, Selectors.DATA_VISIBLE, "false")
118+
dom.setAttr(modal, Selectors.ARIA_MODAL, "true")
119+
dom.setAttr(modal, Selectors.ROLE, "dialog")
120120

121121
const modalButton = dom.find(`[${Selectors.DATA_TARGET}='${modalId}']`)
122122

@@ -171,22 +171,22 @@ export default class Modal {
171171
}
172172

173173
_setActiveModalId() {
174-
this._activeModalId = dom.attr(this._activeModalButton, Selectors.DATA_TARGET)
174+
this._activeModalId = dom.getAttr(this._activeModalButton, Selectors.DATA_TARGET)
175175
}
176176

177177
_setActiveModalOverlay() {
178178
this._activeModalOverlay = dom.find(`[${Selectors.DATA_MODAL}='${this._activeModalId}']`)
179179
}
180180

181181
_removeAttributes() {
182-
dom.attr(this._activeModalOverlay, Selectors.DATA_VISIBLE, "false")
183-
dom.attr(this._activeModalOverlay, Selectors.ARIA_HIDDEN, "true")
184-
dom.attr(this._activeModal, Selectors.TABINDEX, false)
182+
dom.setAttr(this._activeModalOverlay, Selectors.DATA_VISIBLE, "false")
183+
dom.setAttr(this._activeModalOverlay, Selectors.ARIA_HIDDEN, "true")
184+
dom.removeAttr(this._activeModal, Selectors.TABINDEX)
185185
}
186186

187187
_disableFocusOnChildren() {
188188
getFocusableElements(this._activeModalSelector).forEach(element => {
189-
dom.attr(element, Selectors.TABINDEX, "-1")
189+
dom.setAttr(element, Selectors.TABINDEX, "-1")
190190
})
191191
}
192192

@@ -205,8 +205,8 @@ export default class Modal {
205205
}
206206

207207
_setAttributes() {
208-
dom.attr(this._activeModalOverlay, Selectors.ARIA_HIDDEN, "false")
209-
dom.attr(this._activeModalOverlay, Selectors.DATA_VISIBLE, "true")
208+
dom.setAttr(this._activeModalOverlay, Selectors.ARIA_HIDDEN, "false")
209+
dom.setAttr(this._activeModalOverlay, Selectors.DATA_VISIBLE, "true")
210210
if (iOSMobile) dom.css(this._activeModalOverlay, "cursor", "pointer")
211211
}
212212

@@ -220,7 +220,7 @@ export default class Modal {
220220
}
221221

222222
_handleModalFocus() {
223-
dom.attr(this._activeModal, Selectors.TABINDEX, "-1")
223+
dom.setAttr(this._activeModal, Selectors.TABINDEX, "-1")
224224
this._activeModal.focus()
225225
}
226226

@@ -274,9 +274,9 @@ export default class Modal {
274274
}
275275

276276
_handleReturnFocus() {
277-
dom.attr(this._activeModalButton, Selectors.TABINDEX, "-1")
277+
dom.setAttr(this._activeModalButton, Selectors.TABINDEX, "-1")
278278
this._activeModalButton.focus()
279-
dom.attr(this._activeModalButton, Selectors.TABINDEX, false)
279+
dom.removeAttr(this._activeModalButton, Selectors.TABINDEX)
280280
}
281281

282282
_handleScrollRestore() {

src/js/tooltip.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export default class Tooltip {
6464
if (!browserEnv) return
6565

6666
this._allTooltips.forEach(instance => {
67-
const id = dom.attr(instance, Selectors.DATA_TOOLTIP)
67+
const id = dom.getAttr(instance, Selectors.DATA_TOOLTIP)
6868
const trigger = dom.find(this._getTrigger(id), instance)
6969

7070
if (this._activeTooltip || this._activeTrigger) {
@@ -79,7 +79,7 @@ export default class Tooltip {
7979
// private
8080

8181
_setup(instance) {
82-
const tooltipId = dom.attr(instance, Selectors.DATA_TOOLTIP)
82+
const tooltipId = dom.getAttr(instance, Selectors.DATA_TOOLTIP)
8383

8484
if (!tooltipId) {
8585
throw new Error(Messages.NO_ID_ERROR)
@@ -96,8 +96,8 @@ export default class Tooltip {
9696
throw new Error(Messages.NO_TOOLTIP_ERROR(tooltipId))
9797
}
9898

99-
dom.attr(trigger, Selectors.ARIA_DESCRIBEDBY, tooltipId)
100-
dom.attr(tooltip, Selectors.ROLE, "tooltip")
99+
dom.setAttr(trigger, Selectors.ARIA_DESCRIBEDBY, tooltipId)
100+
dom.setAttr(tooltip, Selectors.ROLE, "tooltip")
101101
trigger.addEventListener(Events.MOUSEOVER, this._render)
102102
trigger.addEventListener(Events.FOCUS, this._render)
103103
}
@@ -129,11 +129,11 @@ export default class Tooltip {
129129
}
130130

131131
_setVisibleState() {
132-
dom.attr(this._activeTooltip, Selectors.DATA_VISIBLE, "true")
132+
dom.setAttr(this._activeTooltip, Selectors.DATA_VISIBLE, "true")
133133
}
134134

135135
_setHideState() {
136-
dom.attr(this._activeTooltip, Selectors.DATA_VISIBLE, "false")
136+
dom.setAttr(this._activeTooltip, Selectors.DATA_VISIBLE, "false")
137137
}
138138

139139
_startCloseEvents() {

src/js/utils.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,13 @@ export const browserEnv = typeof window !== "undefined"
2525
* Simple DOM manipulator methods. NOTE: These aren't chainable.
2626
*/
2727
export const dom = {
28-
attr: (element, attr, newValue) => {
29-
if (newValue === false) {
30-
return element.removeAttribute(attr)
31-
}
32-
33-
if (typeof newValue === "string" || newValue === null) {
34-
return element.setAttribute(attr, newValue)
35-
}
36-
37-
return element.getAttribute(attr)
38-
},
28+
getAttr: (element, attr) => element.getAttribute(attr),
29+
setAttr: (element, attr, value) => element.setAttribute(attr, value),
30+
removeAttr: (element, attr) => element.removeAttribute(attr),
3931
hasAttr: (element, attr) => element.hasAttribute(attr),
4032

4133
find: (selector, parent = document) => parent.querySelector(selector),
42-
findAll: (selector, parent = document) => [...parent.querySelectorAll(selector)],
34+
findAll: (selector, parent = document) => Array.apply(null, parent.querySelectorAll(selector)),
4335

4436
css: (element, property, value) => {
4537
if (typeof value === "string" || value === null) {

0 commit comments

Comments
 (0)