Skip to content

Commit 86c96db

Browse files
author
Hesam Bahrami
authored
feat: ordered list support (#41)
* rename the placeholderUL property to placeholderList * remove some empty lines * update the DataEngine class to only render ordered lists * improve JSDoc on the DataEngine class getParentNodeOfItem method * extend the initServerRenderedList function to generate both ol and ul lists * add the getListInterface method * set the listInterface property value upon instantiation * add the getListTagName method * update the NestedSort class to support both ol and ul lists * update one of the samples to contain both ol and ul lists * update the samples CSS code to support both ol and ul lists * add a missing sample code link to the index page * minor comment update
1 parent 7cb47fa commit 86c96db

File tree

8 files changed

+181
-99
lines changed

8 files changed

+181
-99
lines changed

dev/css/main.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ body {
1818
border: 1px solid #ccc;
1919
}
2020

21+
.nested-sort li ol,
2122
.nested-sort li ul {
2223
padding: 0;
2324
margin-top: 10px;
@@ -47,6 +48,6 @@ body {
4748
background-color: rgb(115, 255, 117);
4849
}
4950

50-
.list-group li ul {
51+
.list-group li ol {
5152
margin-top: 10px;
5253
}

dev/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ <h1>Samples</h1>
2222
<li><a href="styling-data-driven-list" target="_blank">Styling</a></li>
2323
<li><a href="data-persistence-in-local-storage" target="_blank">Persisting Data in Local Storage</a></li>
2424
<li><a href="enable-disable" target="_blank">Enable / Disable</a></li>
25+
<li><a href="nesting-levels" target="_blank">Nesting Levels</a></li>
2526
</ol>
2627

2728
</div>

dev/server-rendered-multiple-lists.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ <h1>Multiple server-rendered lists</h1>
1515

1616
<p>The main goal is to create a tree-like list of nested items. You should be able to achieve that by simply dragging and dropping the items using your mouse. Touch screens are not supported yet! 😐</p>
1717

18-
<h2>List 1</h2>
19-
<ul class="draggable">
18+
<h2>List 1: Ordered List</h2>
19+
<ol class="draggable">
2020
<li data-id="1">Topic 1</li>
2121
<li data-id="2">Topic 2</li>
2222
<li data-id="3">Topic 3
23-
<ul data-id="3">
23+
<ol data-id="3">
2424
<li data-id="4">Topic 4</li>
25-
</ul>
25+
</ol>
2626
</li>
2727
<li data-id="5">Topic 5</li>
28-
</ul>
28+
</ol>
2929

30-
<h2>List 2</h2>
30+
<h2>List 2: Unordered List</h2>
3131
<ul class="draggable">
3232
<li data-id="2">Topic 2
3333
<ul data-id="2">

src/data-engine.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class DataEngine {
102102
* @param {HTMLElement} node
103103
* @param {object} item
104104
* @param {string} nodeName
105-
* @returns {HTMLElement|null}
105+
* @returns {Element|null}
106106
*/
107107
getParentNodeOfItem(node, item, nodeName) {
108108
return node.querySelector(`${nodeName}[data-id="${item.parent}"]`)
@@ -123,7 +123,7 @@ class DataEngine {
123123
* @returns {HTMLElement}
124124
*/
125125
getDirectListParentOfItem(node, item) {
126-
return this.getParentNodeOfItem(node, item, 'ul')
126+
return this.getParentNodeOfItem(node, item, 'ol')
127127
}
128128

129129
/**
@@ -142,8 +142,8 @@ class DataEngine {
142142
let directParentList = this.getDirectListParentOfItem(topParent, item)
143143

144144
if (!directParentList) {
145-
// so we need to create the direct parent UL and append it to the direct parent LI
146-
directParentList = this.createItemElement({ id: parent }, 'ul')
145+
// we need to create the direct parent OL and append it to the direct parent LI
146+
directParentList = this.createItemElement({ id: parent }, 'ol')
147147
const directParentListItem = this.getParentNodeOfItem(topParent, item, 'li') || topParent
148148
directParentListItem.appendChild(directParentList)
149149
}
@@ -184,11 +184,11 @@ class DataEngine {
184184
}
185185

186186
/**
187-
* @param {HTMLUListElement} ul
187+
* @param {HTMLOListElement|HTMLUListElement} list
188188
* @returns {object[]}
189189
*/
190-
convertDomToData(ul) {
191-
return Array.from(ul.querySelectorAll('li')).map(li => {
190+
convertDomToData(list) {
191+
return Array.from(list.querySelectorAll('li')).map(li => {
192192
const parentListItem = li.parentNode
193193
const parent = parentListItem.dataset.id
194194
const order = Array.from(parentListItem.children).findIndex(item => item === li) + 1
@@ -202,10 +202,10 @@ class DataEngine {
202202
}
203203

204204
/**
205-
* @returns {HTMLUListElement}
205+
* @returns {HTMLOListElement}
206206
*/
207207
render() {
208-
const list = document.createElement('ul')
208+
const list = document.createElement('ol')
209209
this.getListItemsDom().forEach(listItem => list.appendChild(listItem))
210210
return list
211211
}

src/main.js

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import DataEngine from './data-engine'
22

33
class NestedSort {
4-
54
/**
65
* @constructor
76
* @param {object} [actions={}]
@@ -28,7 +27,7 @@ class NestedSort {
2827
this.data = data
2928
this.selector = el
3029
this.sortableList = null
31-
this.placeholderUl = null
30+
this.placeholderList = null
3231
this.placeholderInUse = null
3332
this.draggedNode = null
3433
this.targetedNode = null
@@ -44,26 +43,22 @@ class NestedSort {
4443
X: null,
4544
Y: null,
4645
}
47-
4846
this.distances = {
4947
droppingEdge,
5048
droppingEdgeNegative: droppingEdge * -1,
5149
mouseTo: {
5250
targetedElTop: undefined,
5351
},
5452
}
55-
5653
this.dimensions = {
5754
targetedEl: {
5855
H: undefined,
5956
},
6057
}
61-
6258
this.cursor = {
6359
X: null,
6460
Y: null,
6561
}
66-
6762
this.classNames = {
6863
dragged: 'ns-dragged',
6964
placeholder: 'ns-placeholder',
@@ -76,15 +71,25 @@ class NestedSort {
7671
dragend: this.onDragEnd.bind(this),
7772
drop: this.onDrop.bind(this),
7873
}
79-
8074
const intNestingLevels = parseInt(nestingLevels)
8175
this.nestingLevels = isNaN(intNestingLevels) ? -1 : intNestingLevels // values less than 0 mean infinite levels of nesting
76+
this.listInterface = this.getListInterface()
8277

8378
this.maybeInitDataDom()
8479
this.addListAttributes()
8580
if (init) this.initDragAndDrop()
8681
}
8782

83+
getListInterface() {
84+
if (Array.isArray(this.data) && this.data.length) return HTMLOListElement
85+
86+
const el = this.selector instanceof HTMLElement
87+
? this.selector
88+
: document.querySelector(this.selector)
89+
90+
return el instanceof HTMLOListElement ? HTMLOListElement : HTMLUListElement
91+
}
92+
8893
getDataEngine() {
8994
if (this.dataEngine instanceof DataEngine) {
9095
return this.dataEngine
@@ -107,14 +112,20 @@ class NestedSort {
107112
wrapper.appendChild(list)
108113
}
109114

115+
getListTagName() {
116+
return this.listInterface === HTMLOListElement ? 'ol' : 'ul'
117+
}
118+
110119
getSortableList() {
111-
if (this.sortableList instanceof HTMLUListElement) return this.sortableList
120+
if (this.sortableList instanceof this.listInterface) return this.sortableList
112121

113-
if (this.selector instanceof HTMLUListElement) {
122+
if (this.selector instanceof this.listInterface) {
114123
this.sortableList = this.selector
115124
} else {
116125
const list = document.querySelector(this.selector)
117-
this.sortableList = list.nodeName === 'UL' ? list : list.querySelector('ul')
126+
this.sortableList = list instanceof this.listInterface
127+
? list
128+
: list.querySelector(this.getListTagName())
118129
}
119130

120131
return this.sortableList
@@ -124,8 +135,8 @@ class NestedSort {
124135
const list = this.getSortableList()
125136

126137
list.classList.add(...this.listClassNames.concat(this.mainListClassName))
127-
list.querySelectorAll('ul').forEach(ul => {
128-
ul.classList.add(...this.listClassNames)
138+
list.querySelectorAll(this.getListTagName()).forEach(l => {
139+
l.classList.add(...this.listClassNames)
129140
})
130141

131142
list.querySelectorAll('li').forEach(li => {
@@ -187,7 +198,7 @@ class NestedSort {
187198

188199
canBeTargeted(el) {
189200
if (!this.draggedNode || this.draggedNode === el) return false
190-
return el.nodeName === 'LI' || (el.nodeName === 'UL' && el.classList.contains(this.classNames.placeholder))
201+
return el.nodeName === 'LI' || (el instanceof this.listInterface && el.classList.contains(this.classNames.placeholder))
191202
}
192203

193204
onDragStart(e) {
@@ -237,7 +248,7 @@ class NestedSort {
237248
getDropLocation() {
238249
if (this.canBeDropped()) {
239250
if (this.targetedNode.nodeName === 'LI' && !this.cursorIsIndentedEnough()) return 'before'
240-
else if (this.targetedNode.nodeName === 'UL') return 'inside'
251+
else if (this.targetedNode instanceof this.listInterface) return 'inside'
241252
}
242253
}
243254

@@ -309,7 +320,8 @@ class NestedSort {
309320
}
310321

311322
targetedNodeIsPlaceholder() {
312-
return this.targetedNode.nodeName === 'UL' && this.targetedNode.classList.contains(this.classNames.placeholder)
323+
return this.targetedNode instanceof this.listInterface
324+
&& this.targetedNode.classList.contains(this.classNames.placeholder)
313325
}
314326

315327
getTargetedNodeDepth() {
@@ -318,7 +330,7 @@ class NestedSort {
318330
const list = this.getSortableList()
319331

320332
while (list !== el.parentElement) {
321-
if (el.parentElement.nodeName === 'UL') depth++
333+
if (el.parentElement instanceof this.listInterface) depth++
322334
el = el.parentElement
323335
}
324336

@@ -345,7 +357,7 @@ class NestedSort {
345357
}
346358
} else if (this.targetedNode !== this.draggedNode
347359
&& this.targetedNode.nodeName === 'LI'
348-
&& !this.targetedNode.querySelectorAll('ul').length
360+
&& !this.targetedNode.querySelectorAll(this.getListTagName()).length
349361
&& !this.nestingThresholdReached()) {
350362
actions.push('add')
351363
}
@@ -376,7 +388,7 @@ class NestedSort {
376388

377389
targetNodeIsListWithItems() {
378390
return this.targetNodeIsIdentified()
379-
&& this.targetedNode.nodeName === 'UL'
391+
&& this.targetedNode instanceof this.listInterface
380392
&& this.targetedNode.querySelectorAll('li').length
381393
}
382394

@@ -388,7 +400,7 @@ class NestedSort {
388400
}
389401

390402
cleanupPlaceholderLists() {
391-
this.getSortableList().querySelectorAll('ul').forEach(ul => {
403+
this.getSortableList().querySelectorAll(this.getListTagName()).forEach(ul => {
392404
if (!ul.querySelectorAll('li').length) {
393405
ul.remove()
394406
} else if (ul.classList.contains(this.classNames.placeholder)) {
@@ -400,12 +412,12 @@ class NestedSort {
400412
}
401413

402414
initPlaceholderList() {
403-
this.placeholderUl = document.createElement('ul')
404-
this.placeholderUl.classList.add(this.classNames.placeholder, ...this.listClassNames)
415+
this.placeholderList = document.createElement(this.getListTagName())
416+
this.placeholderList.classList.add(this.classNames.placeholder, ...this.listClassNames)
405417
}
406418

407419
getPlaceholderList() {
408-
this.placeholderInUse = this.placeholderUl.cloneNode(true)
420+
this.placeholderInUse = this.placeholderList.cloneNode(true)
409421
return this.placeholderInUse
410422
}
411423
}

0 commit comments

Comments
 (0)