markdown 拖放排序:设计与实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown 拖放排序:设计与实现相关的知识,希望对你有一定的参考价值。

Drag-drop sort: Design & Implementation
=======================================

[TOC]


## References

- https://www.v2ex.com/t/400011
- https://www.zhihu.com/question/55789722


## Data Models

Take `Project` and `Task` for example:

```python
class Project(Model):
    pass


class Task(Model):
    POSITION_STEP = 2**16

    project = ForeignKey(Project)
    position = Number(default=POSITION_STEP, allow_none=False)  # position in project it belonged to
```


## Front-end/Server Interaction

The server send tasks by position in ascending order.
The front-end don't need to care `Task.position`. Front-end stores tasks in an ordered list.
While user move a task up/down, just change the ordered list, at the same time send a request telling server the task's new place, like below:

```
## Add a new task with postion-spec

POST /tasks/

{
    "project": "project-001",
    // If you are adding the first task, just ignore the "position" key
    "position": {
        "before": "task-A",	// set null if put at end
        "after": "task-B"	// set null if put at top
    }
    // ...
}


## Update a task with postion-spec

PATCH /tasks/task-C

{
    "project": "project-001",
    "position": {
        "before": "task-A",	// set null if move to the end
        "after": "task-B"	// set null if move to the top
    }
    // ...
}
```

Note the front-end doesn't calculate the position(it's server's responsibility),
also doesn't care the new postision responded by server(because front-end maintains the same order via its ordered list).


## Server Implementation

- When creating the first task, no postion-spec is required from client.
  saving the task with position `65536`(the default value).
- When put a task between two tasks: `position = (before.position + after.position) / 2`
- When put a task at end: `position = after.position + Task.POSITION_STEP`
- When put a task at top: `position = before.position - Task.POSITION_STEP`

If the calculated position is not an integer or `abs(position - after.position) < 2`,
Then all tasks' position values **requires reassignment with the same order**:

Fake code for reassignment:

```python
def rearange_tasks_position(project):
    def make_pos_generator(cursor=1):
        while True:
            yield Task.POSITION_STEP * cursor
            cursor += 1

    pos_generator = make_pos_generator()

    for task in db.query(Task).filter_by(project=project).sort('position', 'ASC').all():
        task.position = next(pos_generator)
        task.save()
```


## Terms

### position-spec

A structure like below:

```json
{
    "before": "some-task-id",
    "after": "some-task-id"
}
```

`before` and `after` mustn't be all missing.

以上是关于markdown 拖放排序:设计与实现的主要内容,如果未能解决你的问题,请参考以下文章

Table Dragger - 简单的 JS 拖放排序表格插件

html 实现托放排序

Android列表视图拖放排序

element+sortablejs插件实现拖拽排序效果

vue 中使用 sortable.js 拖动表格

在管理站点中重定向