main(window);
function main(global) {
const tracker = {};
const domain = createDomain({},q("#record .col-memo").textContent);
const app = tracker;
global.addEventListener("load", initialize);
global.addEventListener("keydown", checkShortKeys);
return;
function q(element, selector) {
// 引数一つはdocumentを起点に検索する
if (arguments.length <= 1)
return q(global.document, element);
/*
* 任意のデータをクエリと解釈する。
* 不適切なクエリの検索結果は空配列とした。
* エラーのほうが適切なのかな……?
*/
var result = []
if (typeof selector == 'string') {
result = element.querySelectorAll(selector);
if(result.length == 1) {
result = result[0];
}
}
return result;
}
function createDomain(domain, firstmemo) {
domain.log = {
start: startLog,
end: endLog,
getLatest: getLatestLog,
private: {
latest: false,
initialize: initializeLog,
},
};
domain.latest= Date.now();
domain.log.private.initialize(firstmemo);
q("#record .col-memo").textContent
return domain;
/*
* 関数宣言
*/
// Log操作
function initializeLog(memo) {
const log = domain.log;
if(log.private.latest) {
return;
}
log.private.latest = {
memo: memo,
start: new Date(),
end: "",
interval: "",
}
}
function getLatestLog() {
return domain.log.private.latest;
}
// 新しい記録を始める。古い記録は終了される。
function startLog(memo, start) {
const log = domain.log;
const secondary = log.private.latest;
// 実質Logオブジェクトを生成している箇所
const primary = {
memo: memo,
start: start,
end: "",
interval: "",
};
secondary.end = start;
// ここが開始-終了の引き算とラップタイムが合わない理由
secondary.interval = Date.now() - domain.latest;
domain.latest = Date.now();
log.private.latest = primary;
return new Promise((resolve, reject) => {
resolve([primary,secondary]);
});
//return primary;
}
function endLog(end) {
}
}
function initialize() {
/*
* アプリケーションオブジェクトの設定
* 後でdefinePropertiesでゲッターを設定する
*/
const ui = {
now: q("#now"),
accesskey: document.forms.one_event.elements.accesskey,
command: document.forms.one_event.elements.command_line,
memo: document.forms.one_event.elements.event_memo,
time: document.forms.one_event.elements.event_time,
addEvent: document.forms.one_event.elements.event_add,
initRec: q("#initial_record"),
get active() {
return document.activeElement;
},
eventLogs: q("#event-logs"),
tmpl: {
eventRec: q("#event_record"),
}
}
const command = {
readyCommand: readyCommand,
readyMemo: readyMemo,
addEvent: addEvent,
getNow: getNow,
}
const data = {
domain: domain,
control: {
get accesskey() {
return tracker.ui.accesskey.checked;
}
},
}
const key = {
//特殊文字
enter: "Enter",
shift: "Shift",
//通常文字
c : "C",
}
Object.defineProperties(tracker, {
ui: {value: ui},
command: {value: command},
key: {value: key},
data: {value: data},
domain:{value: domain},
});
// 初期行の変更
const start = new Date();
const time = start.toLocaleTimeString();
q(tracker.ui.initRec, "td.col-position-start").textContent = time;
// 現在時刻の初回呼び出し、後は自動で1秒ごとに更新。
updateNow(1000);
/*
* コントローラの設定
*/
tracker.ui.addEvent.addEventListener('click', (event) => {
addEvent(tracker.ui.memo.value, tracker.ui.time.value);
})
}
function addEvent(memo, datetime) {
//ISOString形式の例: 14:02:12T00:12:34.000Z"
const today = (new Date(Date.now())).toISOString().substr(0, 10);
let finishTime = ""
if(datetime) {
finishTime = new Date(today + "T" + datetime);
} else {
finishTime = new Date();
}
const newMemo = memo.toString();
domain.log.start(newMemo, finishTime)
.then(value => {
const first = value[0];
const second = value[1];
__addEvent(first, second);
})
function __addEvent(firstLog, secondLog) {
const newTime = firstLog.start.toLocaleTimeString('ja-JP');
const newMemo = firstLog.memo;
const newEvent = q(tracker.ui.tmpl.eventRec.content.cloneNode(true), "tr");
let tr = q(tracker.ui.eventLogs, "tbody tr ");
q(newEvent, "td.col-position-start").textContent = newTime;
q(newEvent, "td.col-memo").textContent = newMemo;
if (tr instanceof Element) { // i.e. 行数1行
insertNewEvent(newEvent, tr, newTime);
} else if (tr.length > 0) { // i.e. 行数2行以上
insertNewEvent(newEvent, tr[0], newTime);
} else { // i.e. 行数0行
q(tracker.ui.eventLogs, "tbody").appendChild(newEvent);
}
function insertNewEvent(first, second, endTime) {
// second行の開始列は作成時に入っている。
const startTime = q(second, "td.col-position-start").textContent;
q(second, "td.col-position-end").textContent = endTime;
q(second, "td.col-interval").textContent = getInterval(startTime, endTime);
q(tracker.ui.eventLogs, "tbody").insertBefore(first, second);
}
function getInterval(start, end) {
const old = tracker.data.domain.latest
tracker.data.domain.latest = Date.now();
let interval = tracker.data.domain.latest - old;
//秒単位にする。ミリ秒以下の数字を先に0にすることで割り切れるようにしてる。
interval = (interval - (interval % 1000)) / 1000
/*
const date = (new Date()).toLocaleDateString("ja-JP");
const before = new Date(date.replaceAll('/', '-') + "T" + start);
const after = new Date(date.replaceAll('/', '-') + "T" + end);
// Dateの起算が1970/1/1/ 00:00:00 (UTC)のため、時刻として時間を求められる。
const interval = before.getTime() - after.getTime();
*/
return interval;
}
}
}
function getNow() {
return tracker.ui.now.textContent.replace(/^.* /, "");
}
function readyCommand() {
readyOf(tracker.ui.command);
}
function readyMemo() {
readyOf(tracker.ui.memo);
}
function readyOf(ui) {
if(tracker.ui.active == ui) {
console.log("do nothing");
return;
}
neutral();
ui.focus();
}
function neutral() {
for ( elem in tracker.ui) {
if((elem instanceof Element) && (elem.hasFocus())) {
elem.blur();
}
}
}
function checkShortKeys(event) {
if((!event.shiftKey) || (!tracker.data.control.accesskey)) {
return;
}
const binds = tracker.key
switch (event.key) {
case binds.c:
if( tracker.ui.command !== tracker.ui.active ) {
tracker.command.readyCommand();
} else {
console.log("do nothing");
}
break;
case binds.enter:
tracker.command.readyMemo();
break;
}
}
function updateNow(interval) {
const start = new Date();
const time = start.toLocaleDateString() + " " + start.toLocaleTimeString();
tracker.ui.now.textContent = time;
setTimeout(updateNow, interval, interval);
}
}