DIR : /home/kozerus/public_html/jkwii/js/jsdoit/jsdoit18/index.js
/home/kozerus/public_html/jkwii/js/jsdoit/jsdoit18
// forked from beryujp's "ぺたぺた貼るToDoリスト" http://jsdo.it/beryujp/ptodo
// forked from edo_m18's "Simple ToDo管理アプリ with HTML5" http://jsdo.it/edo_m18/stodo
/**
* 自分の画像を背景に、使い方それぞれなToDo管理アプリ
* @author beryujp
*/
(function(win, doc, $, exports) {
var ToDoApp = {
STORAGE : window.localStorage,
DBNAME : 'todo',
FILEDBNAME : 'todobg',
INDEX : 0,
CONTAINER : 'taskPane',
CURRENT : null,
ADDFLG : false,
/**
* 初期化
* 初期化はINDEXの取得、設定
*/
initialize: function() {
this.INDEX = this.getIndex() || 0;
// 背景画像が保存済みでなければデフォルト画像を設定
if(!this.STORAGE[this.FILEDBNAME]) {
this.STORAGE[this.FILEDBNAME] = JSON.stringify({dataSchema: 'http://jsrun.it/assets/j/9/O/O/j9OO9.jpg'});
}
this.setBackground(JSON.parse(this.STORAGE[this.FILEDBNAME]));
},
/**
* ToDoをリストに追加する
*
* @param {String} txt ToDoに設定するテキスト.
* @param {Number} id ToDoのユニークID
* @param {Number} x 表示場所(X座標)
* @param {Number} y 表示場所(Y座標)
*/
addToDo: function(txt, id, x, y){
var data;
/**
* 渡されたIDのデータを取得
* もしデータがあればそれを更新する
*/
data = this.getData(id);
//各プロパティの正規化
data || (data = {});
data.groupID || (data.groupID = 0);
data.complete || (data.complete = 0);
data.txt = txt;
data.tid = id;
data.x = x;
data.y = y;
//設定した情報を保存
this.setData(data, id);
this.update();
this.ADDFLG = false;
},
/**
* ToDoを完了状態にする
*
* @param {Number} id 完了にする対象のToDo ID
*/
completeToDo: function(id) {
var data = this.getData(id);
//コンプリートフラグを1(=完了)に
data.complete = 1;
//フラグを更新してデータを保存
this.setData(data, id);
this.update();
},
/**
* ToDoを削除する
*
* @param {Number} id 削除するToDoのID
*/
removeToDo: function(id) {
var data,
i = 0, l;
if (!confirm('このToDoを削除しますか?')) {
return false;
}
//いったん全データを取得
data = this.getData();
//該当するデータを検索
for (l = data.length; i < l; i++) {
if (data[i].tid == id) {
data.splice(i,1);
break;
}
}
//更新したデータリストを保存
this.setData(data);
this.update();
},
/**
* ToDoを変更
*
* @param {Number} id 変更するToDoのID
*/
changeToDo: function(id, x, y) {
var txt = $('input.todoTxt', '#todo' + id).val();
this.addToDo(txt, id, x, y);
},
/**
* ToDoの追加フォームを生成する
*/
createToDoForm: function(e) {
var id;
if (this.isID(this.CURRENT) || this.ADDFLG) {
return;
}
this.ADDFLG = true;
/*
if ($('#noToDo').length === 1) {
$('#noToDo').remove();
}
*/
id = this.getIndex();
id = !isNaN(id) ? id : 0;
$('#taskPane').append([
'<a id="todo' + id + '" class="todoItem" style="top:' + e.offsetY + 'px; left:' + e.offsetX + 'px;">',
'<input type="text" class="todoTxt" value="" placeholder="ToDoアイテム" onclick="event.stopPropagation();"/> ',
'<input type="button" value="save" onclick="ToDoApp.changeToDo(' + id + ', ' + e.offsetX + ', ' + e.offsetY + '); event.stopPropagation();" /> ',
'<input type="button" value="x" onclick="ToDoApp.cancel(); event.stopPropagation();" />',
'</a>'].join(''));
$('input.todoTxt:visible').keyup(function(event) {
ToDoApp.keyupHandler(event, id);
}).focus();
},
/**
* ToDoアイテムのKeyupイベントハンドラ
*/
keyupHandler: function(event, id) {
if(event.keyCode == 13) { // enter
ToDoApp.changeToDo(id,
$('#todo'+id).css('left').substr(0, $('#todo'+id).css('left').length - 2),
$('#todo'+id).css('top').substr(0, $('#todo'+id).css('top').length - 2));
} else if(event.keyCode == 27) { // escape
ToDoApp.cancel();
}
},
/**
* ToDoの更新フォームを生成する
*/
replaceToDoForm: function(item,evt) {
var id, data;
/**
* クリックされた対象がinput要素か、
* すでに完了しているものの場合はなにもしない
*/
if (evt.target.nodeName.toLowerCase() === 'input') {
return;
}
if (evt.currentTarget.className.indexOf('complete') !== -1) {
return;
}
if (!this.isID(this.CURRENT)) {
id = parseInt($(item).attr('data-id'),10);
data = this.getData(id);
if (!isNaN(id) && data) {
$(item)
.after([
'<a id="todo' + id + '" class="todoItem" style="top:' + data.y + 'px; left:' + data.x + 'px;">',
'<input type="text" class="todoTxt" value="' + data.txt + '" onclick="event.stopPropagation();"/> ',
'<input type="button" value="save" onclick="ToDoApp.changeToDo(' + id + ', ' + data.x + ', ' + data.y + '); event.stopPropagation();" /> ',
'<input type="button" value="x" onclick="ToDoApp.cancel(); event.stopPropagation();" />',
'</a>'].join(''))
.remove();
$('#todo' + id + ' input.todoTxt:visible').keyup(function(event) {
ToDoApp.keyupHandler(event, id);
}).focus();
}
}
evt.stopPropagation();
},
/**
* 現在のindex数を取得する
*/
getIndex: function() {
var o = this.getData();
if(!o) {
return null;
}
// 最大値を求める
var max = 0;
for(var l = o.length - 1; l >= 0; l--) {
if(parseInt(o[l].tid) > max) {
max = parseInt(o[l].tid);
}
}
return ++max;
},
/**
* ToDoデータをlocalStorageから取得する
*
* @param {Number} id 取得したいToDoのID
* @returns {Object} 取得したToDoデータリスト
*/
getData: function(id) {
var db = this.STORAGE[this.DBNAME],
json,
i = 0, l;
//データが存在していなければ初期化を実行する
(db) || this.clear();
//JSONデータをチェック。データが存在しなければ正規化
json = JSON.parse(this.STORAGE[this.DBNAME]);
(json) || (json = {});
(json.data) || (json.data = []);
// X座標、Y座標初期化
for(i = json.data.length; i >= 0; i-- ) {
if(json.data && json.data[i] && json.data[i].x == undefined) {
json.data[i].x = 10;
json.data[i].y = 30 * i;
}
}
i = 0;
//IDが指定されていなかったらデータすべてを返す
if (!this.isID(id)) {
return json.data;
}
//指定されたIDのデータを返す
for (l = json.data.length; i < l; i++ ) {
if (json.data[i].tid == id) {
return json.data[i];
}
}
//該当IDが存在しなければnullを返す
return null;
},
/**
* @param {Object} data
* @param {Number} id
*/
setData: function(data, id) {
var d,
i = 0, l;
if (!this.isID(id)) {
this.STORAGE[this.DBNAME] = JSON.stringify({data: data});
}
else {
d = this.getData();
update: {
for (l = d.length; i < l; i++) {
if (d[i].tid == id) {
d[i] = data;
break update;
}
}
d[d.length] = data;
}
this.STORAGE[this.DBNAME] = JSON.stringify({data:d});
}
},
/**
* idが数値かどうかを判定
*/
isID: function(id) {
return typeof id === 'number';
},
/**
* ToDoリストをアップデートする
*
* @param {Number} id アップデート対象のToDo ID
*/
update: function(id) {
var data,
groups = {}, index = 1, gid,
i = 0, l,
compFlg, element, ele,
that = this;
if (this.isID(id)) {
data = this.getData(id);
}
else {
data = this.getData();
//いったん全ToDoデータを画面から削除
$('#' + this.CONTAINER).html('');
//ToDoがひとつも登録されていなければそれを表示
if (!data || !data[0]) {
$('#todo').append('<p id="noToDo">ToDoが登録されていません。</p>');
return false;
}
//完了状態を元にソート(完了したものがリストの下に移動するように)
/*
data = data.sort(function(a, b) {
return a.complete - b.complete;
});
*/
for (l = data.length; i < l; i++) {
gid = 'g' + data[i].groupID;
/*
if (!groups[gid]) {
groups[gid] = $('<div class="groupBox" />');
groups[gid].attr('data-gid', data[i].groupID);
groups[gid].append('<p class="ttlGroup">ToDo List</p>');
}
$('#' + this.CONTAINER).append(groups['g' + data[i].groupID]);
*/
//完了状態をチェック
compFlg = data[i].complete ? ' complete' : '';
element = [
'<a id="todo{{id}}" class="{{class}}" data-id="{{id}}" style="top:{{posY}}px;left:{{posX}}px;">',
'<span class="todoTxtItem">{{todotext}}</span>',
'<div class="todoCtrl">',
'<input type="button" value="done" onclick="ToDoApp.completeToDo({{id}}); event.stopPropagation();" class="btnComp" /> ',
'<input type="button" value="x" onclick="ToDoApp.removeToDo({{id}}); event.stopPropagation();" class="btnDel" />',
'</div>',
'<div class="todoCtrl2">',
'<input type="button" value="resume" onclick="ToDoApp.resume({{id}}); event.stopPropagation();" class="btnResume" />',
'<input type="button" value="x" onclick="ToDoApp.removeToDo({{id}}); event.stopPropagation();" class="btnDel" />',
'</div>',
'</div>'
].join('');
//要素のテンプレートからそれぞれToDoのデータで置き換え
element = element.replace(/{{id}}/ig, data[i].tid);
element = element.replace(/{{class}}/ig, 'todoItem' + compFlg);
element = element.replace(/{{todotext}}/ig, data[i].txt);
element = element.replace(/{{posY}}/ig, data[i].y);
element = element.replace(/{{posX}}/ig, data[i].x);
//生成したToDoアイテムをリストに追加
//ele = groups['g' + data[i].groupID].append(element);
ele = $('#' + this.CONTAINER).append(element);
}
/**
* 生成したToDoアイテムにクリックと
* hoverイベントを設定
*/
$('.todoItem')
.click(function(e) {
that.replaceToDoForm(this, e);
e.stopPropagation();
})
.hover(function() {
that.status('クリックで編集できます。');
},
function() {
that.statusClear();
}).draggable({
stop: function(event, ui) {
that.addToDo($('#todo' + ui.helper[0].dataset['id'] + ' .todoTxtItem').html(),
parseInt(ui.helper[0].dataset['id']), ui.position.left, ui.position.top);
event.stopPropagation();
}
});
}
},
/**
* 完了状態にしたToDoを再開する(完了状態を解除する)
*
* @param {Number} id 完了状態をオフにするToDoのID
*/
resume: function(id) {
var data = this.getData(id);
//完了状態をオフに
data.complete = 0;
//完了状態を更新してアップデート
this.setData(data, id);
this.update();
},
/**
* 更新・追加フォームの状態をキャンセルする
*/
cancel: function() {
this.update();
this.ADDFLG = false;
},
/**
* データベース(localStorage)とリストを初期化(クリア)する
*/
clear: function() {
this.STORAGE[this.DBNAME] = JSON.stringify({data:[]});
this.INDEX = 0;
//画面に表示しているリストを削除
$('#' + this.CONTAINER).html('');
},
/**
* 全ToDoを削除する
*/
clearAction: function() {
if (this.isID(this.CURRENT)) {
return;
}
if (confirm('ToDoをクリアします。この処理は取り消せません。本当に実行しますか?')) {
this.clear();
this.update();
}
},
/**
* ステータスバーにメッセージを表示
*
* @param {String} mes 表示するメッセージ
*/
status: function(mes) {
$('#status').html(mes);
},
statusClear: function() {
$('#status').html('');
},
/**
* 背景画像がドロップされた時の動作
*/
onFileDrop: function(event) {
// ドロップされたファイルのfilesプロパティを参照
var files = event.dataTransfer.files;
var reader = new FileReader();
var disp = document.getElementById("disp");
// FileReaderにイベントを登録
reader.onload = this.onLoadComplete;
// ブラウザ上でファイルを展開する挙動を抑止
event.preventDefault();
// 読み込み開始
reader.readAsDataURL(files[0]);
/*
disp.innerHTML = "";
for (var i = 0; i < files.length; i++) {
var f = files[i];
// ファイル名とサイズを表示
disp.innerHTML += "ファイル名 :" + f.name + "ファイルの型:" + f.type + "ファイルサイズ:" + f.size / 1000 + " KB " + "<br />";
}
*/
},
/**
* HTML5のドラッグ操作のお決まりごと
* 参考:http://cpplover.blogspot.jp/2009/09/quirksblog-html5.html
*/
onFileDragOver: function(event) {
// ブラウザ上でファイルを展開する挙動を抑止
event.preventDefault();
},
/**
* ファイルロード完了ハンドラ
*/
onLoadComplete: function(event) {
window.ToDoApp.STORAGE[window.ToDoApp.FILEDBNAME] = JSON.stringify({dataSchema: event.target.result});
window.ToDoApp.setBackground({dataSchema: event.target.result});
},
/**
* localStorage内の画像を背景に設定
*/
setBackground: function(json) {
if(json.dataSchema) {
$('#taskPane').css('background', 'url("' + json.dataSchema + '")');
}
},
/**
* localStorage内の画像を初期画像に戻す
*/
resetBackground: function() {
delete window.ToDoApp.STORAGE[window.ToDoApp.FILEDBNAME];
window.ToDoApp.initialize();
}
};
//アプリの初期化を実行
ToDoApp.initialize();
/* ----------------------------------------------------------------------------------
EXPORT
グローバルからアクセスできるように変数をエクスポート
------------------------------------------------------------------------------------- */
exports.ToDoApp = ToDoApp;
}(window, document, jQuery, window));
//ページ読み込み後に、アプリを実行する
$(function() { ToDoApp.update(); });
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer