◆ input イベントを監視して idle/timeout イベントを起こす
◆ 入力後に指定時間の間操作がないと idle
◆ 指定時間以上 idle イベントが起きず入力が続いていると timeout
◆ これを使って自動保存やプレビュー更新などをする

入力した後にしばらく入力がない状態になったらプレビューを更新したり ストレージに自動保存したりなどをする機能はけっこう使うのですが 毎回作るのが面倒になったので 使いまわせそうな感じにまとめました

function observeInput(elem, option) {
let ti = null
let tt = null
const default_option = { timeout: 1000 * 20, idle: 1000 * 6 }

elem.addEventListener("input", () => {
if (tt === null) {
tt = setTimeout(() => {
tt = null
elem.dispatchEvent(new Event("timeout"))
}, ~~option.timeout || default_option.timeout)
}

clearTimeout(ti)
ti = setTimeout(() => {
clearTimeout(tt)
tt = null
elem.dispatchEvent(new Event("idle"))
}, ~~option.idle || default_option.idle)
})
}

input イベントを監視して idle イベントと timeout イベントを起こします

idle 判定する時間を指定しておいて 入力からその時間があいたら idle 状態と判定して idle イベントを起こします
その時間以内で入力が続いてる限りは idle イベントが起きません

休みなく入力中も適度に更新や保存したい場合のために timeout イベントもあります
こっちは指定した時間が経つとイベントが起きるもので基本は setTimeout のようなものです
idle と連動しているので idle イベントが起きると発生せず idle が起きずに入力から指定時間経つとイベントを発生させます
入力がずっと続いていれば setInterval のように定期的に発生することになります

使い方の例

const input = document.getElementById("input")
input.addEventListener("idle", () => {
console.log("idle")
})
input.addEventListener("timeout", () => {
console.log("timeout")
})
observeInput(input, { timeout: 7000, idle: 2000 })

input とオプションで時間を指定したら その input からイベントが起きるようになるので addEventListener でイベントに対する処理を設定します
複数 input 全体に対して idle 判定するなら それらの親の div などを渡してもいいです



これを使った自動保存の例です

// option: {target: HTMLElement, collect: Function, key: String}
function autosaver(option) {
observeInput(option.target, option)
option.target.addEventListener("idle", () => {
save()
})
option.target.addEventListener("timeout", () => {
save()
})

function save() {
if (!running) return
const data = option.collect()
const json = JSON.stringify(data)
localStorage[option.key || "autosave"] = json
}

let running = false

return {
start() { running = true },
stop() { running = false },
}
}

これがライブラリ部分です
使い方はこうです

<div id="d">
<input id="n" type="number">
<input id="s" type="text">
</div>

<script>
autosaver({
target: document.getElementById("d"),
collect() {
return {
n: +document.getElementById("n").value,
s: document.getElementById("s").value,
}
},
}).start()
</script>

target に要素で collect にイベントが起きたときに保存するデータを作る処理を入れます
key で localStorage のキーを設定できますが 省略すれば autosave というキーになります
collect で返したオブジェクトが JSON で設定されます