Skip to content

Commit

Permalink
Specify the doc.subscribe event value - move operation
Browse files Browse the repository at this point in the history
- To test the move operation, add `drag&drop` to the todo example
  • Loading branch information
chacha912 committed Mar 30, 2023
1 parent 1be1d8a commit 31e4015
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 30 deletions.
81 changes: 76 additions & 5 deletions public/multi.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ <h2>yorkie document</h2>
await client.activate();

// 02. create a document then attach it into the client.
const doc = new yorkie.Document('multi-example');
const doc = new yorkie.Document('multi-example11');

doc.subscribe((event) => {
console.log('🟢 doc event', event);
Expand Down Expand Up @@ -180,18 +180,27 @@ <h2>yorkie document</h2>

function addTodo(text) {
const newTodo = document.createElement('li');
newTodo.classList.add('todoItem');
newTodo.setAttribute('draggable', 'true');
const todoText = document.createElement('span');
todoText.classList.add('item_name');
todoText.classList.add('itemName');
todoText.textContent = text;
const deleteButton = document.createElement('button');
deleteButton.classList.add('trash');
deleteButton.textContent = '🗑';

const moveUpButton = document.createElement('button');
moveUpButton.classList.add('moveUp');
moveUpButton.textContent = '⬆';
const moveDownButton = document.createElement('button');
moveDownButton.classList.add('moveDown');
moveDownButton.textContent = '⬇';

newTodo.appendChild(moveUpButton);
newTodo.appendChild(moveDownButton);
newTodo.appendChild(todoText);
newTodo.appendChild(deleteButton);
todoList.appendChild(newTodo);
}

function handleAddTodo() {
const text = todoInput.value;
if (text === '') {
Expand All @@ -204,13 +213,35 @@ <h2>yorkie document</h2>
});
}

let dragIndex = -1;
function handleDragStart(i) {
console.log('👻 drag start', i);
dragIndex = i;
}
function handleDragOver(e, i) {
e.preventDefault();
if (dragIndex === i) return;
console.log('👻 drag over', e, i);
swapTodo(dragIndex, i);
dragIndex = i;
}
function handleDragEnd() {
console.log('👻 drag end');
dragIndex = -1;
}
function swapTodo(dragIdx, dropIdx) {
doc.update((root) => {
const dragged = root.todos.splice(dragIdx, 1)[0];
root.todos.splice(dropIdx, 0, dragged);
});
}

addTodoButton.addEventListener('click', handleAddTodo);
todoInput.addEventListener('keypress', (event) => {
if (event.key === 'Enter') {
handleAddTodo();
}
});

todoList.addEventListener('click', function (e) {
if (e.target.classList.contains('trash')) {
const $li = e.target.parentNode;
Expand All @@ -219,7 +250,47 @@ <h2>yorkie document</h2>
const todoID = root.todos.getElementByIndex(idx).getID();
root.todos.deleteByID(todoID);
});
return;
}
if (e.target.classList.contains('moveUp')) {
const $li = e.target.parentNode;
const idx = Array.from($li.parentNode.children).indexOf($li);
if (idx === 0) return;
doc.update((root) => {
const nextItem = root.todos.getElementByIndex(idx - 1);
const currItem = root.todos.getElementByIndex(idx);
root.todos.moveBefore(nextItem.getID(), currItem.getID());
});
return;
}
if (e.target.classList.contains('moveDown')) {
const $li = e.target.parentNode;
const idx = Array.from($li.parentNode.children).indexOf($li);
if (idx === doc.getRoot().todos.length - 1) return;
doc.update((root) => {
const prevItem = root.todos.getElementByIndex(idx + 1);
const currItem = root.todos.getElementByIndex(idx);
root.todos.moveAfter(prevItem.getID(), currItem.getID());
});
return;
}
});
todoList.addEventListener('dragstart', function (e) {
const $li = e.target.closest('.todoItem');
if (!$li) return;
const idx = Array.from($li.parentNode.children).indexOf($li);
handleDragStart(idx);
});
todoList.addEventListener('dragover', function (e) {
const $li = e.target.closest('.todoItem');
if (!$li) return;
const idx = Array.from($li.parentNode.children).indexOf($li);
handleDragOver(e, idx);
});
todoList.addEventListener('dragend', function (e) {
const $li = e.target.closest('.todoItem');
if (!$li) return;
handleDragEnd();
});

// 05. Quill example
Expand Down
23 changes: 19 additions & 4 deletions public/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,36 @@ button {
overflow-y: auto;
}
.todoList li {
padding: 10px 0 10px 20px;
display: flex;
padding: 10px;
font-size: 0.9em;
}
.todoList li:hover,
.todoList li:focus {
background: #e2e2e2;
}
.todoList li .item_name {
display: inline-block;
width: 84%;
.todoList li .itemName {
padding: 0 10px;
flex: 1;
word-break: break-all;
}
.todoList .trash {
background: transparent;
border: none;
}
.todoList .moveUp,
.todoList .moveDown {
background: #fff;
border-radius: 10px;
border: none;
margin-right: 4px;
color: #666;
}
.todoList .trash:hover,
.todoList .moveUp:hover,
.todoList .moveDown:hover {
scale: 1.1;
}
.todoNew {
display: flex;
border-top: 1px solid #ddd;
Expand Down
2 changes: 1 addition & 1 deletion src/document/json/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ export class ArrayProxy {
}

/**
* `moveAfterInternal` moves the given `createdAt` element
* `moveLastInternal` moves the given `createdAt` element
* at the last of array.
*/
public static moveLastInternal(
Expand Down
3 changes: 1 addition & 2 deletions src/document/operation/add_operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,11 @@ export class AddOperation extends Operation {
const value = this.value.deepcopy();
array.insertAfter(this.prevCreatedAt, value);
root.registerElement(value, array);
const index = Number(array.subPathOf(this.getEffectedCreatedAt()));
return {
type: 'add',
element: this.getParentCreatedAt(),
value: value instanceof Primitive ? value.getValue() : value,
index: isNaN(index) ? undefined : index,
index: Number(array.subPathOf(this.getEffectedCreatedAt())),
};
}

Expand Down
35 changes: 21 additions & 14 deletions src/document/operation/move_operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import { logger } from '@yorkie-js-sdk/src/util/logger';
import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket';
import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root';
import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array';
import { Operation } from '@yorkie-js-sdk/src/document/operation/operation';
import {
Operation,
Modified,
} from '@yorkie-js-sdk/src/document/operation/operation';

/**
* `MoveOperation` is an operation representing moving an element to an Array.
Expand Down Expand Up @@ -58,22 +61,26 @@ export class MoveOperation extends Operation {
/**
* `execute` executes this operation on the given `CRDTRoot`.
*/
public execute(root: CRDTRoot): void {
public execute(root: CRDTRoot): Modified {
const parentObject = root.findByCreatedAt(this.getParentCreatedAt());
if (parentObject instanceof CRDTArray) {
const array = parentObject as CRDTArray;
array.moveAfter(
this.prevCreatedAt!,
this.createdAt,
this.getExecutedAt(),
);
} else {
if (!parentObject) {
logger.fatal(`fail to find ${this.getParentCreatedAt()}`);
}

if (!parentObject) {
logger.fatal(`fail to find ${this.getParentCreatedAt()}`);
}
if (!(parentObject instanceof CRDTArray)) {
logger.fatal(`fail to execute, only array can execute move`);
}
const array = parentObject as CRDTArray;
const previousIndex = Number(array.subPathOf(this.createdAt));
array.moveAfter(this.prevCreatedAt, this.createdAt, this.getExecutedAt());
const index = Number(array.subPathOf(this.createdAt));
console.log(previousIndex, index);

return {
type: 'move',
element: this.getParentCreatedAt(),
index,
previousIndex,
};
}

/**
Expand Down
13 changes: 10 additions & 3 deletions src/document/operation/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ export type AddOpModified = {
type: 'add';
element: TimeTicket;
value: CRDTElement | PrimitiveValue;
index: number | undefined;
index: number;
};
export type MoveOpModified = {
type: 'move';
element: TimeTicket;
previousIndex: number;
index: number;
};
export type SetOpModified = {
type: 'set';
Expand All @@ -36,7 +42,7 @@ export type RemoveOpModified = {
type: 'remove';
element: TimeTicket;
key?: string;
index?: number | undefined;
index?: number;
};
export type IncreaseOpModified = {
type: 'increase';
Expand All @@ -47,7 +53,8 @@ export type Modified =
| AddOpModified
| IncreaseOpModified
| RemoveOpModified
| SetOpModified;
| SetOpModified
| MoveOpModified;

/**
* `Operation` represents an operation to be executed on a document.
Expand Down
2 changes: 1 addition & 1 deletion src/document/operation/remove_operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class RemoveOperation extends Operation {
? {
type: 'remove',
element: this.getEffectedCreatedAt(),
index: isNaN(Number(key)) ? undefined : Number(key),
index: Number(key),
}
: {
type: 'remove',
Expand Down

0 comments on commit 31e4015

Please sign in to comment.