scrapbox-pomodoro

PageMenuUserScriptyosider
date-fns使

workbreak
work, break
Notification.requestPermission()
work

2021-03-31 16:31:15
s/format/lightFormat
2021-03-14 05:45:50 takker
get
Notification.requestPermission()constructorthis.stop2?
constructor requestPermission() stop() takker
requestPermission() stop()
constructor takker
stopyosider
PageMenuonClickyosider
await
workPeriod
global
moduleglobaltakker
export const workPeriod import import {workPeriod} from ... import
yosider
ESModule便takkertakker
References

TODO
done
stopWork, stopBreak
2021/3/14 21:21 doneyosider
Scrapbox
Scrapbox project
local storage
yosider
Eugene Schwartz3333

(async () => {
const {Pomodoro} = await import('/api/code/programming-notes/scrapbox-pomodoro/script.js');
new Pomodoro({workPeriod: 5 * 1000, breakPeriod: 1 * 1000});
})();
importyosider
takker

/yosider-scriptsprivateyosider
takker
/programming-notes
import { addMilliseconds, lightFormat } from '../date-fns.min.js/script.js';
const title = 'Pomodoro Timer';
const image = 'https://gyazo.com/978797f03cb0112a0a4cafdf02dcdde8/raw';
const notificationOptions = { body: `With 🍅 by ${title}`, icon: image };
export class Pomodoro {
constructor({workPeriod, breakPeriod} = {}) {
scrapbox.PageMenu.addMenu({title, image, onClick: () => Pomodoro.requestPermission()});
this.menu = scrapbox.PageMenu(title);
//Pomodoro.requestPermission();

Function.prototype.bind()使takker
JavaScriptthis#e0ea7f () => this.stopBreak()
yosider
this.start() 使takker
-this.start(workPeriod, this.stopWork);
+this.start(workPeriod, () => this.stopWork());
yosider
scrapbox-pomodoro#361d0b
this.reset() constructor() takker
constructor() 使
stopresetreset使yosider
stop2reset
//this.stopBreak = this.stopBreak.bind(this);
//this.stopWork = this.stopWork.bind(this);
this.isRunning = false;
this.isWorkPeriod = false;
this.intervalID = undefined;
this.startTime = undefined;
this.endTime = undefined;
this.timeoutID = undefined;
this.workPeriod = workPeriod ?? 25 * 60 * 1000;
this.breakPeriod = breakPeriod ?? 5 * 60 * 1000;
this.setItems(this.startWorkButton);
}
//
get startWorkButton() { return { title: '\uf04b Start Work', onClick: () => this.startWork() };}
get stopWorkButton() { return { title: '\uf04d Stop Work', onClick: () => this.stopWork() };}
get startBreakButton() { return { title: '\uf0f4 Start Break ', onClick: () => this.startBreak() };}
get stopBreakButton() { return { title: '\uf04d Stop Break', onClick: () => this.stopBreak() };}
get timerDisplay() { return { title: '--:--', onClick: () => { } };}
setItems(...items) {
this.menu.removeAllItems();
items.forEach(i => this.menu.addItem(i));
}
start(period, callback) {
this.isRunning = true;
this.startTime = new Date();
this.endTime = addMilliseconds(this.startTime, period);
this.intervalID = setInterval(() => callback(), period);
this.setUpdateTimerLoop();
}
startWork() {
this.start(this.workPeriod, () => this.stopWork(''));
this.setItems(this.timerDisplay, this.stopWorkButton);
}
startBreak() {
this.start(this.breakPeriod, () => this.stopBreak(''));
this.setItems(this.timerDisplay, this.stopBreakButton);
}
stop(msg='') {
this.isRunning = false;
clearTimeout(this.timeoutID);
clearInterval(this.intervalID);
}
stopWork(msg='') {
this.stop();
this.setItems(this.startBreakButton);
if (msg) new Notification(msg, notificationOptions);
const endTime = new Date();
const page = `/${scrapbox.Project.name}/${encodeURIComponent(lightFormat(endTime, 'yyyy/M/d'))}`;
const log = `${lightFormat(this.startTime, 'HH:mm')} -> ${lightFormat(endTime, 'HH:mm')}: [${scrapbox.Page.title}]\n`;
window.open(`${page}?body=${encodeURIComponent(log)}`);
}
stopBreak(msg='') {
this.stop();
this.setItems(this.startWorkButton);
if (msg) new Notification(msg, notificationOptions);
}
setUpdateTimerLoop() {
if (!this.isRunning) return;

FIXME: item0 commit messagetakker
yosider
item
itemtitle
setUpdateTimerLoop() item[0] takker
addItemyosider
this.menu.menus.get(title).items[0].title = lightFormat(this.endTime - new Date(), 'mm:ss'); // item0
this.menu.emitChange();
this.timeoutID = setTimeout(() => this.setUpdateTimerLoop(), 1000);
}
static requestPermission() {
if (Notification.permission === 'granted') return;
if (Notification.permission === 'denied') throw Error('Permission denied.');
// UI
const a = document.createElement('a');
a.onclick = async () => {
const state = await Notification.requestPermission();
if (state !== 'granted') throw Error('Permission denied.');
};
document.body.appendChild(a);
a.click();
a.remove();
}
}