Skip to content

Instantly share code, notes, and snippets.

@gutchom
Last active April 20, 2017 06:55
Show Gist options
  • Save gutchom/f34c293188c6689d63736aa016ff969f to your computer and use it in GitHub Desktop.
Save gutchom/f34c293188c6689d63736aa016ff969f to your computer and use it in GitHub Desktop.
オブジェクトを与えることで画面の状態や操作の履歴を保存したり復元したりしてくれるよ。
interface HistoryLogger {
readonly current: any
readonly stamp: number
jump(stamp: number): void
undo(): void
redo(): void
clear(): void
record(record: any): void
restore(): void
}
import moment from 'moment'
const PREFIX = 'log-'
export default class Logger implements HistoryLogger {
version: string
name: string
history: any[] = [] // index1番が最古の状態。this.history.length - 1が最新。
retroactDepth = 0 // this.history.lengthが最大値。
restorableDepth: number
marks: { timestamp: number, position: number }[] = []
noStorage: boolean = false
constructor(version: string, name: string, restorableDepth: number) {
this.version = version
this.name = name
this.restorableDepth = restorableDepth
try {
if (typeof window.sessionStorage === 'undefined') this.noStorage = true
const x = '__storage_test__'
localStorage.setItem(x, x)
localStorage.removeItem(x)
this.noStorage = false
}
catch (err) {
this.noStorage = true
}
}
private get minDepth(): number { return 0 }
private get maxDepth(): number { return this.history.length - 1 }
private get depth(): number { return this.retroactDepth }
private set depth(num: number) {
this.retroactDepth = num <= this.minDepth
? this.minDepth
: num >= this.maxDepth
? this.maxDepth
: num
this.marks = this.marks.filter(mark => mark.position < this.history.length)
}
get current(): any { return this.history[this.history.length - this.depth - 1] }
get stamp(): number {
const timestamp = Date.now()
const position = this.history.length - this.depth
this.marks.push({ timestamp, position })
return timestamp
}
undo(): void { this.depth++ }
redo(): void { this.depth-- }
clear(): void {
this.history = []
this.depth = this.minDepth
}
jump(stamp: number): void {
const mark = this.marks.find(mark => mark.timestamp === stamp)
if (!mark) throw new Error('Assigned stamp to logger is outdated.')
this.depth = this.history.length - mark.position
}
record(data: any): void {
const index = this.history.length - this.depth
this.history.splice(index, this.depth, data)
if (this.noStorage) return
const depth = - (this.depth + this.restorableDepth)
const log = {
version: this.version,
timestamp: moment().format(),
depth: this.retroactDepth,
data: this.history.slice(depth),
}
localStorage.setItem(PREFIX + this.name, JSON.stringify(log))
}
restore(): void {
if (this.noStorage) return
const json = localStorage.getItem(PREFIX + this.name)
if (!json) return
const restored = JSON.parse(json)
if (restored.version !== this.version) return
if (moment().diff(moment(restored.timestamp), 'hours', true) > 3) return
this.depth = restored.depth
this.history = restored.data
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment