npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

unredo2

v0.1.2

Published

Undo & Redo Action in JavaScript

Downloads

2

Readme

Unredo

Undo & Redo Action in JavaScript

npm i unredo2 --save

撤销/重做模块。主要包含三个类,CommandCommandManagerSynthetiseCommand

Command

我们把用户的操作行为都抽象为一种类:Command,一个 Command 包含用户操作的两个方面:执行和撤销。

Command 是一个抽象的类,不要直接实例化它,没什么卵用。你只能继承它来定义需要的 Command;继承 Command 的时候你必须重写它的两个方法,exec(执行)和 rollback(撤销),两者为一一对应的正反操作。

e.g.

import { Command } from 'unredo'

class InsertImageCommand extends Command {
  constructor (img) {
    this.img = img
  }

  exec () {
    document.body.appendChild(this.img)
  }

  rollback () {
    document.body.removeChild(this.img)
  }
}

const img = document.createElement('img')
img.src = "http://baidu.com"
const insertBaiduImgCommand = new InsertImageCommand(img)


/* 插入删除同一张照片 */
insertBaiduImgCommand.exec() // 插入
insertBaiduImgCommand.roolback() // 删除
insertBaiduImgCommand.exec() // 插入
insertBaiduImgCommand.roolback() // 删除
...

Command 就是一个用户操作的执行和回滚的基本单元。对于一个用户操作复杂的应用,你可能需要自定义很多 Command。但有时候我们不是像上面那样直接执行 execrollback 函数,因为有可能用户的实际操作和程序上的撤销重做不是完全一样的(例如用户操作的时候有动画,而程序回滚和撤销没有动画),这时候可能就是额外写一些逻辑,这些逻辑和 exec 的结果一样,但是过程不一样。实际上对于用户交互丰富的程序来说,execrollback 你可能不需要调用,它们是提供给 CommandManager 内部调用的。

CommandManager

用户的一系列操作可能由不同的 Command 组合而成,CommandManager 就是帮助你维护用户在这一系列操作当中的的撤销、重做。一个用户场景一般来说你只需要实例化一个 CommandManager 就够了。CommandManager 有几个方法

  • add
  • backwards
  • forwards
  • clear

用法就是:只要用户进行操作了,你就用 CommandManager 往里面 add Command,用户撤销就 backwards(),用户重做就 forwards();要重置和清空所有历史操作就用 clear()

import { Command, CommandManager } from 'unredo'

class InsertImageCommand extends Command {...}
class DeleteImageCommand extends Command {...}
class InsertDivCommand extends Command {...}
class DeleteDivCommand extends Command {...}

const commandManager = new CommandManager()

// 事件监听都是伪代码
$(window).on('ctrl + i', () => {
  const insertImage = new InsertImageCommand(...)
  // 插入图片逻辑
  // ...
  
  commandManager.add(insertImage)
})

$(window).on('ctrl + k', () => {
  const deleteImage = new DeleteImageCommand(...)
  // ...
  commandManager.add(deleteImage)
})

$(window).on('ctrl + j', () => {
  const insertDiv = new InsertDivCommand(...)
  // ...
  commandManager.add(insertDiv)
})

$(window).on('ctrl + z', () => {
  commandManager.backwards() // 撤销,内部调用 rollback
})

$(window).on('ctrl + shift + z', () => {
  commandManager.forwards() // 重做,内部调用 exec
})

commandManager.add 其实只会把命令 push 到一个队列里面,而不会执行 Commandexec 操作。上面的 // ... 就是所说的结果一样但行为不一样的额外逻辑。

SynthetiseCommand

很经常有一些操作是由多个操作组合而成的操作,例如说把 C 节点从 A 节点移动到 B 节点,这一个 “移动” 操作其实是由 “删除” 和 “插入” 两个动作组合而成。但其实对于用户来说这一个 “移动” 操作只是一个操作(撤销和重做都是一个单元),所以就有了 SynthetiseCommand,它可以把多个操作的组合操作变成一个新的操作。

e.g.

import { Command, CommandManager, SynthetiseCommand } from 'unredo'

class DeleteNodeCommand extends Command {...}
class AddNodeCommand extends Command {...}

const commandManager = new CommandManager()

const moveNodeFromTo = (node, from, to) => {
  const deleteNodeCommand = new DeleteNodeCommand(node, from)
  const addNodeCommand = new DeleteNodeCommand(node, to)

  const moveCommand = new SynthetiseCommand()
  moveCommand.add(deleteNodeCommand)
  moveCommand.add(addNodeCommand) // 这两个命令合成了一个 move 命令

  // ...额外逻辑

  commandManager.add(moveCommand)
}