-
Notifications
You must be signed in to change notification settings - Fork 152
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export default class LinkedItem { | ||
constructor() { | ||
this.next = null; | ||
this.prev = null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
export default class LinkedList { | ||
constructor() { | ||
this.head = null; | ||
this.tail = null; | ||
} | ||
prepend(item) { | ||
this.insertBefore(item, this.head); | ||
} | ||
append(item) { | ||
this.insertBefore(item, null); | ||
} | ||
insertAfter(item, prevItem) { | ||
let nextItem = null; | ||
if (prevItem) { | ||
nextItem = prevItem.next; | ||
} | ||
this.insertBefore(item, nextItem); | ||
} | ||
insertBefore(item, nextItem) { | ||
this.remove(item); | ||
if (nextItem && nextItem.prev) { | ||
// middle of the items | ||
let prevItem = nextItem.prev; | ||
item.next = nextItem; | ||
nextItem.prev = item; | ||
item.prev = prevItem; | ||
prevItem.next = item; | ||
} else if (nextItem) { | ||
// first item | ||
if (this.head === nextItem) { | ||
item.next = nextItem; | ||
nextItem.prev = item; | ||
} else { | ||
this.tail = item; | ||
} | ||
this.head = item; | ||
} else { | ||
// last item | ||
if (this.tail) { | ||
item.prev = this.tail; | ||
this.tail.next = item; | ||
} | ||
if (!this.head) { | ||
this.head = item; | ||
} | ||
this.tail = item; | ||
} | ||
} | ||
remove(item) { | ||
if (item.next && item.prev) { | ||
// Middle of the list | ||
item.next.prev = item.prev; | ||
item.prev.next = item.next; | ||
} else { | ||
if (item === this.head) { | ||
// Head of the list | ||
if (item.next) { | ||
item.next.prev = null; | ||
} | ||
this.head = item.next; | ||
} | ||
if (item === this.tail) { | ||
// Tail of the list | ||
if (item.prev) { | ||
item.prev.next = null; | ||
} | ||
this.tail = item.prev; | ||
} | ||
} | ||
item.prev = null; | ||
item.next = null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
const {module, test} = QUnit; | ||
|
||
import LinkedList from 'content-kit-editor/utils/linked-list'; | ||
import LinkedItem from 'content-kit-editor/utils/linked-item'; | ||
|
||
module('Unit: Utils: LinkedList'); | ||
|
||
test('initial state', (assert) => { | ||
let list = new LinkedList(); | ||
assert.equal(list.head, null, 'head is null'); | ||
assert.equal(list.tail, null ,'tail is null'); | ||
}); | ||
|
||
['append', 'prepend', 'insertBefore', 'insertAfter'].forEach(method => { | ||
test(`#${method} initial item`, (assert) => { | ||
let list = new LinkedList(); | ||
let item = new LinkedItem(); | ||
list[method](item); | ||
assert.equal(list.head, item, 'head is item'); | ||
assert.equal(list.tail, item, 'tail is item'); | ||
assert.equal(item.next, null, 'item next is null'); | ||
assert.equal(item.prev, null, 'item prev is null'); | ||
}); | ||
}); | ||
|
||
test(`#append second item`, (assert) => { | ||
let list = new LinkedList(); | ||
let itemOne = new LinkedItem(); | ||
let itemTwo = new LinkedItem(); | ||
list.append(itemOne); | ||
list.append(itemTwo); | ||
assert.equal(list.head, itemOne, 'head is itemOne'); | ||
assert.equal(list.tail, itemTwo, 'tail is itemTwo'); | ||
assert.equal(itemOne.prev, null, 'itemOne prev is null'); | ||
assert.equal(itemOne.next, itemTwo, 'itemOne next is itemTwo'); | ||
assert.equal(itemTwo.prev, itemOne, 'itemTwo prev is itemOne'); | ||
assert.equal(itemTwo.next, null, 'itemTwo next is null'); | ||
}); | ||
|
||
test(`#prepend first item`, (assert) => { | ||
let list = new LinkedList(); | ||
let itemOne = new LinkedItem(); | ||
let itemTwo = new LinkedItem(); | ||
list.prepend(itemTwo); | ||
list.prepend(itemOne); | ||
assert.equal(list.head, itemOne, 'head is itemOne'); | ||
assert.equal(list.tail, itemTwo, 'tail is itemTwo'); | ||
assert.equal(itemOne.prev, null, 'itemOne prev is null'); | ||
assert.equal(itemOne.next, itemTwo, 'itemOne next is itemTwo'); | ||
assert.equal(itemTwo.prev, itemOne, 'itemTwo prev is itemOne'); | ||
assert.equal(itemTwo.next, null, 'itemTwo next is null'); | ||
}); | ||
|
||
test(`#insertBefore a middle item`, (assert) => { | ||
let list = new LinkedList(); | ||
let itemOne = new LinkedItem(); | ||
let itemTwo = new LinkedItem(); | ||
let itemThree = new LinkedItem(); | ||
list.prepend(itemOne); | ||
list.append(itemThree); | ||
list.insertBefore(itemTwo, itemThree); | ||
assert.equal(list.head, itemOne, 'head is itemOne'); | ||
assert.equal(list.tail, itemThree, 'tail is itemThree'); | ||
assert.equal(itemOne.prev, null, 'itemOne prev is null'); | ||
assert.equal(itemOne.next, itemTwo, 'itemOne next is itemTwo'); | ||
assert.equal(itemTwo.prev, itemOne, 'itemTwo prev is itemOne'); | ||
assert.equal(itemTwo.next, itemThree, 'itemTwo next is itemThree'); | ||
assert.equal(itemThree.prev, itemTwo, 'itemThree prev is itemTwo'); | ||
assert.equal(itemThree.next, null, 'itemThree next is null'); | ||
}); | ||
|
||
test(`#insertAfter a middle item`, (assert) => { | ||
let list = new LinkedList(); | ||
let itemOne = new LinkedItem(); | ||
let itemTwo = new LinkedItem(); | ||
let itemThree = new LinkedItem(); | ||
list.prepend(itemOne); | ||
list.append(itemThree); | ||
list.insertAfter(itemTwo, itemOne); | ||
assert.equal(list.head, itemOne, 'head is itemOne'); | ||
assert.equal(list.tail, itemThree, 'tail is itemThree'); | ||
assert.equal(itemOne.prev, null, 'itemOne prev is null'); | ||
assert.equal(itemOne.next, itemTwo, 'itemOne next is itemTwo'); | ||
assert.equal(itemTwo.prev, itemOne, 'itemTwo prev is itemOne'); | ||
assert.equal(itemTwo.next, itemThree, 'itemTwo next is itemThree'); | ||
assert.equal(itemThree.prev, itemTwo, 'itemThree prev is itemTwo'); | ||
assert.equal(itemThree.next, null, 'itemThree next is null'); | ||
}); | ||
|
||
test(`#remove an only item`, (assert) => { | ||
let list = new LinkedList(); | ||
let item = new LinkedItem(); | ||
list.append(item); | ||
list.remove(item); | ||
assert.equal(list.head, null, 'head is null'); | ||
assert.equal(list.tail, null, 'tail is null'); | ||
assert.equal(item.prev, null, 'item prev is null'); | ||
assert.equal(item.next, null, 'item next is null'); | ||
}); | ||
|
||
test(`#remove a first item`, (assert) => { | ||
let list = new LinkedList(); | ||
let itemOne = new LinkedItem(); | ||
let itemTwo = new LinkedItem(); | ||
list.append(itemOne); | ||
list.append(itemTwo); | ||
list.remove(itemOne); | ||
assert.equal(list.head, itemTwo, 'head is itemTwo'); | ||
assert.equal(list.tail, itemTwo, 'tail is itemTwo'); | ||
assert.equal(itemOne.prev, null, 'itemOne prev is null'); | ||
assert.equal(itemOne.next, null, 'itemOne next is null'); | ||
assert.equal(itemTwo.prev, null, 'itemTwo prev is null'); | ||
assert.equal(itemTwo.next, null, 'itemTwo next is null'); | ||
}); | ||
|
||
test(`#remove a second item`, (assert) => { | ||
let list = new LinkedList(); | ||
let itemOne = new LinkedItem(); | ||
let itemTwo = new LinkedItem(); | ||
list.append(itemOne); | ||
list.append(itemTwo); | ||
list.remove(itemTwo); | ||
assert.equal(list.head, itemOne, 'head is itemOne'); | ||
assert.equal(list.tail, itemOne, 'tail is itemOne'); | ||
assert.equal(itemOne.prev, null, 'itemOne prev is null'); | ||
assert.equal(itemOne.next, null, 'itemOne next is null'); | ||
assert.equal(itemTwo.prev, null, 'itemTwo prev is null'); | ||
assert.equal(itemTwo.next, null, 'itemTwo next is null'); | ||
}); | ||
|
||
test(`#remove a middle item`, (assert) => { | ||
let list = new LinkedList(); | ||
let itemOne = new LinkedItem(); | ||
let itemTwo = new LinkedItem(); | ||
let itemThree = new LinkedItem(); | ||
list.append(itemOne); | ||
list.append(itemTwo); | ||
list.append(itemThree); | ||
list.remove(itemTwo); | ||
assert.equal(list.head, itemOne, 'head is itemOne'); | ||
assert.equal(list.tail, itemThree, 'tail is itemThree'); | ||
assert.equal(itemOne.prev, null, 'itemOne prev is null'); | ||
assert.equal(itemOne.next, itemThree, 'itemOne next is itemThree'); | ||
assert.equal(itemTwo.prev, null, 'itemTwo prev is null'); | ||
assert.equal(itemTwo.next, null, 'itemTwo next is null'); | ||
assert.equal(itemThree.prev, itemOne, 'itemThree prev is itemOne'); | ||
assert.equal(itemThree.next, null, 'itemThree next is null'); | ||
}); |