2017年4月5日水曜日

時間帯を色分けするhtaを改良

前verからの変更内容は以下の通りです。
・カウント中に積算時間が表示されるようにした。
・設定・記録内容を保存・読み込みできるようにした。
・指定した日時に終了・開始の記録を追加できるようにした。
・画面内レイアウト変更
などなど。




起動画面



カウント中の様子



「出力」ボタンを押すと以下の小窓が表示されます。
※小窓を閉じると一時フォルダと一時ファイルは自動的に削除されます。



「入力」ボタンを押すとドロップ用エレメントが表示されます。
このエレメント上に「出力」で作成したファイルをドロップすると、出力時のデータが読み込まれます。



「挿入」ボタンを押すと挿入用インターフェースが表示されます。
日時は省略表記に対応しています。



以下ソース
<html>
<head>
<title>時間帯の色分け</title>
<style type="text/css">
.max{width:100%;height:100%}
.w-max{width:100%}
.nowrap{white-space:nowrap}
.ta-c{text-align:center}
.bc{border-collapse:collapse}
.of-auto{overflow:auto}
.of-hidden{overflow:hidden}
.border1{border:solid 1px #000}
</style>
</head>
<body class=of-hidden>
<table class="bc max">
<tr height=1>
<td>
<table class="w-max bc">
<td width=1><select id=sel></select></td>
<td><div id=div0 class="of-auto nowrap border1" style="width:100%;height:40px"></div></td>
<td width=1><button id=btn開始>開始</button><button id=btn終了 style="display:none">終了</button></td>
<td width=1><button id=btn出力>出力</button></td>
<td width=1><button id=btn入力>入力</button></td>
<td width=1><button id=btn挿入>挿入</button></td>
</table>
</td>
</tr>
<tr>
<td>
<table class="bc max" border=1>
<td width=300>
<table id=tbl色 class="w-max bc" border=1>
<tr>
<td>colorCode</td>
<td>種類</td>
<td>積算</td>
<td>現在</td>
</tr>
<tr>
<td width=75><input class=w-max></td>
<td><input class=w-max></td>
<td width=1><span class=nowrap style="background-color:#fff"></span></td>
<td width=1><input type=radio name=色 style="zoom:2"></td>
</tr>
</table>
<button id=btn色追加>色追加</button>
</td>
<td>
<table class="max bc" border=1>
<tr height=1><td>内容</td><td><select id=sel内容 class=w-max></select></td></tr>
<tr><td width=60>コメント</td><td><textarea id=ta class=max wrap=off></textarea></td></tr>
<tr height=1><td>開始</td><td id=td開始></td></tr>
<tr height=1><td>終了</td><td id=td終了></td></tr>
<tr height=1><td>期間</td><td id=td期間></td></tr>
</table>
</td>
</table>
<td>
</tr>
</table>
</body>
<script>
resizeTo(800,480)
me=function(){return arguments.callee.caller}
bgc=function(elem, color){elem.style.backgroundColor = '#'+color}
onload=function(){
var ops=sel.options, i=0
ops[i++] = new Option('全体',0)
ops[i++] = new Option('分' ,1000*60)
ops[i++] = new Option('時間',1000*60*60)
ops[i++] = new Option('日' ,1000*60*60*24)
ops[i++] = new Option('週' ,1000*60*60*24*7)
ops[i++] = new Option('月' ,1000*60*60*24*31)
ops[i++] = new Option('年' ,1000*60*60*24*365)
// 最初は文字列型になっているが内容なども記録するのでオブジェクト型に変える
for0L(arr色,function(i,str){arr色[i] = {code:arr色[i]} })
var tbo=tbl色[FI], tr=tbo[FI][NE].removeNode(true), newTR, ops=sel内容[OP]
var fun色=function(i,obj色){
tbo[iB](newTR=tr.cloneNode(true))
bgc(ops[i] = new Option(obj色.内容 || ''), obj色.code)
var cn=newTR[CN], inp0=cn[0][FI], inp1=cn[1][FI], span=cn[2][FI], rad=cn[3][FI]
bgc(newTR, inp0.value=obj色.code)
inp0.onchange=function(){
var str=this.value
if(!str){
if(arr記録.length){
alert('開始後は色追加は可能ですが削除はできません')
return this.value = obj.code
}else{
if(!confirm('['+obj色.code+']を削除しますか?')){ return this.value = obj色.code }
}
arr色 = arr色.slice(0,i).concat(arr色.slice(i+1,arr色.length))
return 色の種類表示を初期化()
}
bgc(this[PA][PA], obj色.code=str)
bgc(ops[i], str)
}
inp1.onchange=function(){ ops[i].text = arr色[i].内容 = this.value }
rad.onclick=function(){ chg(i) }
}
色の種類表示を初期化=function(){
while(tbo[CN][1]){ tbo[CN][1].removeNode(true) }
while(ops[0]){ops[0] = null}
for0L(arr色,fun色)
}
色の種類表示を初期化()
btn色追加.onclick=function(){
var code='cccccc', obj={code:code}
fun色(arr色.push(obj)-1, obj)
}
}
arr記録 = []
arr色 = ['E60012', 'F39800', 'FFF100', '009944', '0068B7', '1D2088', '920783']
インターバル={
開始:function(){ this.クリア用obj = setInterval(帯を表示, this.間隔) },
終了:function(){ clearInterval(this.クリア用obj); 帯を表示() },
クリア用obj:null,
間隔:1000
}
sel.onchange=function(){ 帯を表示() }
桁=function(num,桁数){
var str0=num+'', str1=Array(桁数+1).join(0)+num
return (桁数 < str0.length) ? str0 : str1.slice(str1.length-桁数,str1.length)
}
ms2日時=function(ms){with(new Date(ms)){return [getFullYear(), 桁(getMonth()+1,2),桁(getDate(),2)].join('/')+' '+[桁(getHours(),2),桁(getMinutes(),2),桁(getSeconds(),2)].join(':')}}
帯を表示=function(){
var 単位=sel.options[sel.selectedIndex].value-0, d=document.createElement('span'), newD
var 今=gt(), 最後=arr記録[arr記録.length-1], 期間=(最後.str=='終了' ? 最後.t : 今) - arr記録[0].t
div0.innerText = ''
d.height='20px'
var f=function(i){
var 開始=arr記録[i].t, 終了=arr記録[i+1] ? arr記録[i+1].t : 今
div0.insertBefore(newD=d.cloneNode(true))
bgc(newD, arr色[arr記録[i].i].code)
newD.onmouseover = function(){
ta.onchange()
ta.value = arr記録[i].コメント || ''
sel内容[sI] = arr記録[i].i || 0
sel内容.onchange.i = i
td開始.innerText = ms2日時(開始)
td終了.innerText = ms2日時(終了)
td期間.innerText = time単位(終了-開始)
ta.onchange.i = i
}
newD.style.width = ((終了-開始) / (単位 || 期間) * 100) + '%'
}
for(var i=0,L=arr記録.length-1;i<L;i++){ f(i) }
最後.str!='終了' && f(i)
積算表示()
}
sel内容.onchange=function(){
var i=arguments.callee.i
if(!isFinite(i)){return}
arr記録[i].i = this[sI]
帯を表示()
}
ta.onchange=function(){
var i=arguments.callee.i
if(!isFinite(i)){return}
arr記録[i].コメント = this.value
}
btn開始.onclick = function(){
if(!arr記録[LEN]){return alert('開始時の色を選択してから開始ボタンを押してください')}
btn終了.style.display = 'block'
this.style.display = 'none'
インターバル.開始()
}
btn終了.onclick = function(){
this.style.display = 'none'
btn開始.style.display = 'block'
arr記録.push({t:gt(), str:'終了', i:arr記録[arr記録[LEN]-1].i})
インターバル.終了()
}
btn出力.onclick=function(){
var dir=fso.gsf2+'/'+gt()
fso.AXO.CreateFolder(dir)
閉じたら削除する(dir)
var path=dir+'/'+ms2日時(gt()).replace(/[\/:]/g,'')+'.txt', arr=[]
var obj変換={'\\\\':'\\\\', '"':'\\"', '\\r':'\\r', '\\n':'\\n'}
forIn(obj変換, function(name,v){obj変換[name] = {R:new RegExp(name,'g'), v:v}})
var エスケープ=function(str){return forIn(obj変換,function(n,o){ str = str.replace(o.R, o.v) }), str}
var arr2str=function(arr){
var arr0=[]
for0L(arr,function(i,obj){
var arr1=[], j=0
forIn(obj,function(name,v){ arr1[j++] = '"'+エスケープ(name)+'" : "'+エスケープ(v+'')+'"' })
arr0[i] = '\t{\n\t\t'+arr1.join(',\n\t\t')+'\n\t}'
})
return '[\n'+arr0.join(',\n')+'\n]'
}
var str記録='記録 = '+arr2str(arr記録), str色='色 = '+arr2str(arr色)
fso.Write(path, (str記録+'\n\n'+str色).replace(/\n/g,'\r\n'))
}
btn入力.onclick=function(){
var div=document.createElement('div')
document.body[iB](div)
div[iH] = '<iframe style="position:absolute;top:0;left:0" class=max src="about:blank"></iframe>'
var ifr=div[FI], d=ifr.contentWindow.document
d.open()
d.write('ここにファイルをドロップしてください<br>ドロップエリア内をクリックするとドロップエリアが非表示になります')
d.close()
d.body.onclick = function(){ div.removeNode(true) }
ifr.onreadystatechange=function(){
if(this.readyState!='complete'){return}
var str=this.contentWindow.document.body.innerText, 記録, 色
div.removeNode(true)
eval(str)
arr色 = 色
arr記録 = 記録
for0L(記録,function(i,obj){ obj.i -=0; obj.t -= 0 })
色の種類表示を初期化()
帯を表示()
}
}
btn挿入.onclick=function(){
var div=document.body[iB](document.createElement('div')), td
div[iH] = '<table onclick="event.cancelBubble=true" style="position:absolute;top:0;left:0;background-color:#fff" class=max src="about:blank"><td class=ta-c></td></table>'
;(td = div[FI][FI][FI][FI])[iH] = '<select></select><input><button>挿入</button><button>キャンセル</button><br><span></span>'
var cn=td[CN], sel=cn[0], inp=cn[1], btnOK=cn[2], btnCancel=cn[3], op=sel[OP], span=cn[5]
for0L(sel内容[OP], function(i,elem){ bgc(op[i] = new Option(elem.text), arr色[i].code) })
inp.onkeyup=inp.onchange=function(){ span[iT] = str2dat(this.value) }
btnOK.onclick=function(){
var t=span[iT], d=new Date(t), ms=gt(d)
if(!t || -1<t.indexOf('NaN')){return inp.select(), alert('日時が不正です')}
var f=function(i){ arr記録 = arr記録.slice(0,i).concat({t:ms, i:sel[sI]}).concat(arr記録.slice(i,arr記録[LEN])) }
if(!for0L(arr記録,function(i,obj){return obj.t < ms ? 0 : (f(i), true)})){ f(arr記録[LEN]) }
帯を表示()
div.removeNode(true)
}
btnCancel.onclick=function(){ div.removeNode(true) }
}
積算表示=function(){
var obj結果={}, 最後=arr記録.length-1
var f=function(i, ms){ obj結果[i] = (obj結果[i] || 0) + ms }
for0L(arr記録,function(i,obj){ i!=最後 && f(obj.i, arr記録[i+1].t - obj.t) })
arr記録[最後].str!='終了' && f(arr記録[最後].i, gt() - arr記録[最後].t)
for0L(arr色,function(i,obj){
var ms=obj結果[i] || 0
tbl色[FI][CN][1+i][CN][2][FI][iT] = ms ? time単位(ms) : ''
})
}
time単位=function(ミリ秒){
// 値の大きさに応じて「秒」「分」「時間」などの単位に直した文字列を返す。
var f=function(){return Math.round(ミリ秒/1000/num*10)/10}, num=1
if(ミリ秒 < 1000 * 60){return f()+'秒'}
if(ミリ秒 < 1000 * (num=60) * 60){return f()+'分'}
if(ミリ秒 < 1000 * (num=60 * 60) * 24){return f()+'時間'}
if(ミリ秒 < 1000 * (num=60 * 60 * 24) * 7){return f()+'日'}
if(ミリ秒 < 1000 * (num=60 * 60 * 24) * 31){return f(num*=7)+'週'}
if(ミリ秒 < 1000 * (num=60 * 60 * 24) * 365){return f(num*=31)+'月'}
num = 60 * 60 * 24 * 365
return f()+'年'
}
chg=function(i){ arr記録.push({t:gt(), i:i}) }
gt=function(d){return (d || new Date()).getTime()}
閉じたら削除する=function(pathDIR){
var pathJS=fso.gsf2+'/'+gt()+'.js', pathHTA=pathJS+'.hta'
fso.Write(pathJS, '('+function(){
AXO=function(name){return new ActiveXObject(name)}
fs=AXO('Scripting.FileSystemObject')
arg=WScript.Arguments
AXO('WScript.Shell').Run(arg(0), 1, true)
待機回数 = 0
while(true){
try{
fs.DeleteFolder(arg(1))
break
}catch(e){ WScript.Echo(1000 * 10) }
if(待機回数++ > 100){break}
}
fs.DeleteFile(arg(0))
fs.DeleteFile(WScript.ScriptFullName)
}+')()')
var X=(window.screenLeft || window.screenX || 0) + (window.innerWidth || document.body.cliendWidth || document.documentElement.clientWidth || 300) / 2
var Y=(window.screenTop || window.screenY || 0) + (window.innerHeight || document.body.cliendHeight || document.documentElement.clientHeight || 300) / 2
fso.Write(pathHTA,(''+function(){/*
<-title>-path-<-/title>
<-iframe style="width:100%;height:100%" src="-path-"><-/iframe>
<-script>
resizeTo(300,300)
moveTo(-x- - 150, -y- - 150)
<-/script>
*/}).split('/*')[1].split('*/')[0].replace(/<-/g,'<').replace(/-path-/g,pathDIR).replace(/-x-/,X).replace(/-y-/,Y))
shell.run(pathDQ(pathJS)+' '+pathDQ(pathHTA)+' '+pathDQ(pathDIR))
}
FI='firstChild', iB='insertBefore', CN='childNodes', LEN='length', iT='innerText', iH='innerHTML', PA='parentNode', NE='nextSibling', sI='selectedIndex', OP='options'
for0L = function(arr,fun){for(var i=0,L=arr[LEN],res;i<L;i++){if(res=fun(i,arr[i])){return res}}}
forIn = function(obj,fun){var name,res; for(name in obj){if(res=fun(name, obj[name])){return res}}}
AXO=function(name){return new ActiveXObject(name)}
shell=AXO('WScript.Shell')
pathDQ=function(path){return 0<path.indexOf(' ') ? ('"'+path+'"') : path}
fso=function(){
var fs=AXO('Scripting.FileSystemObject')
return {
AXO:fs,
gsf2:fs.GetSpecialFolder(2), // Z:\TEMP
Read:function(path, swCreate, swUnicode){
if(!fs.FileExists(path)){return}
with(fs.OpenTextFile(path, 1, swCreate, swUnicode)){ var str=AtEndOfStream ? '' : ReadAll(); Close() }
return str
},
Write:function(path,str,swUnicode,sw上書きしない){ with(fs.CreateTextFile(path, !sw上書きしない, swUnicode)){ Write(str); Close() } }
}
}()
str2dat=function(){
// var 桁=function(num,桁数){var str0=num+'', str1=Array(桁数+1).join(0)+num; return (桁数 < str0.length) ? str0 : str1.slice(str1.length-桁数,str1.length)}
var nd=function(){
var toStr=function(フォーマット){
// フォーマットは「YY/MM/DD hh:mm:ss」のような文字列
var d=this.dat, obj={Y:d.getFullYear(), M:d.getMonth()+1, D:d.getDate(), h:d.getHours(), m:d.getMinutes(), s:d.getSeconds()}, chr, reg, res
for(chr in obj){
reg = new RegExp(chr+'+')
res = フォーマット.match(reg)
if(!res){continue}
フォーマット = フォーマット.replace(reg, 桁(obj[chr], res[0].length))
}
return フォーマット
}
return function(d){
return { dat:d || (new Date()), toStr:toStr }
}
}()
var R=RegExp
var rY=/^[^\d]*(\d{4})\//, rMD=/(\d{1,2})\/(\d{1,2})/, rHM=/(\d{1,2}):(\d{1,2})/, rYMD=/(\d{4})\/?(\d{2})\/?(\d{2})/, rFull=/(\d{4})\/?(\d{2})\/?(\d{2}) *(\d{2}):?(\d{2})/, rD2D2=/(\d{2})(\d{2})[^\d]*?$/
return function(str, datBA, swBefore){
// datBA(Dateオブジェクト)は有っても無くてもOK
// datBAを指定するとdatBAよりも(swBeforeがfalseなら後ろ、trueなら前)の日時を返す。
var str0=str, obj={}, rC=function(){str0=R.rightContext}
if(str0 && str0.match(rFull)){ obj={Y:R.$1, M:R.$2, D:R.$3, h:R.$4, m:R.$5}, str0='' }
if(str0 && str0.match(rY)){ obj.Y=R.$1, rC() }
if(str0 && str0.match(rMD)){ obj.M=R.$1, obj.D=R.$2, rC() }
if(str0 && str0.match(rHM)){ obj.h=R.$1, obj.m=R.$2, rC() }
if(str0 && str0.match(rYMD)){ obj.Y=R.$1, obj.M=R.$2, obj.D=R.$3, rC() }
if(str0 && str0.match(rD2D2)){ obj.h=R.$1, obj.m=R.$2, str0=R.leftContext }
if(str0 && str0.match(rD2D2)){ obj.M=R.$1, obj.D=R.$2, str0=R.leftContext }
var d=nd(), Y=obj.Y || d.toStr('Y'), M=obj.M || d.toStr('M'), D=obj.D || d.toStr('D'), h=obj.h || d.toStr('h'), m=obj.m || d.toStr('m')
var str1 = [Y,M,D].join('/') + (obj.h ? (' '+[h,m].join(':')) : ''), dat=new Date(str1)
if(datBA && !isNaN(dat) && !obj.Y){
var T=datBA.getTime()
while((!swBefore && (dat.getTime() <= T)) || (swBefore && (T <= dat.getTime()))){
if(isFinite(obj.M)){ dat.setFullYear(dat.getFullYear()+(swBefore?-1:1)) }else{ dat.setDate(dat.getDate()+(swBefore?-1:1)) }
}
}
return nd(dat).toStr('Y/MM/DD hh:mm:ss')
}
}()
</script>
</html>


0 件のコメント:

コメントを投稿