todoリスト:PCアプリケーションソフトの作り方(html・javascript構成)

todoリスト:PCアプリケーションソフトの作り方(html・javascript構成)

todoリスト:PCアプリケーションソフトの作り方(html・javascript構成)

完全にオフラインで保存できる、htmlとjavascriptを使ったtodoリストのPCアプリケーションソフトです。

IndexedDBがメインで主要ブラウザで稼働し、PC版Safariでも稼働するようポリフィル経由のWebSQLも導入しています。

ネット回線を切っても稼働する様manifestファイルの読込も紹介しています。

完全オフラインで保存できるtodoリスト

みなさんよく目にするTodoリスト。やらなければならない項目を書き入れておき、その項目が完了したら消していくリストですね。

ブラウザ上でこのTodoリストを準備・入力して使っている人も大勢いると思います。

しかしこういったアプリケーションをオフラインで動作・保存させるにはどのようにすれば良いのでしょうか。

今回はオフライン利用・保存できるブラウザアプリケーション

ほとんどの場合、そのアプリケーションはインターネットにつながっている状態が条件ですよね。

本記事では完全にオフライン(ローカル環境)で利用できるtodoリストツールを構築する方法をご紹介します。

ブラウザを閉じたりPC自体を終了しても、本データはきちんと保存されます。

通常のWordやメモ帳などと同じ様に使えるツールです。

PCブラウザで動くtodoリスト作成のポイント

PCブラウザソフトとなる、オフラインtodoリストアプリケーションのポイントを確認しておきます。

・ユーザーによりToDoリストの項目を追加および削除可能
・インターネットに接続せずに読込
・全てのデータをローカルに保存(バックエンドなし)
・ブラウザは最新バージョンで実行(IE以外の主要ブラウザ)

Google Chrome、Firefox、Edge、Safariなどのブラウザでは動作確認済みです。

利用する技術

・IndexedDB
・WebSQL

IndexedDB

IndexedDBとは値とオブジェクトをローカルデータベースに保持するWEBブラウザの標準インターフェースです。

localStorageよりもストレージ容量が大きく使いやすいメリットがあります。

WebSQL

WebSQLはWEBブラウザ内でデータベースを利用できるツールです。SQL文を利用したデータベースの操作ができます。

データベースはCookieと同様の形でクライアントサイドに格納されるため、複数のブラウザ間でデータ保存ができない点があります。

今回は対応ブラウザを考慮し両方を併用

基本的にはIndexedDBのみで動きますが、今回は「IndexedDBポリフィル」を使用してWebSQLもサポートしています。

このポリフィルによるWebSQLを使わないと、PC版のSafariブラウザでは動きません。

あくまでオフライン環境であらゆるブラウザに対応するため、今回は両方を併用します。

全てのブラウザがIndexedDBをサポートする様になれば、ポリフィルを削除する事ができます。

IEでは本PCソフトは動きません。

アプリケーションソフト構成

以下のファイル構成を一つのフォルダ内に作りましょう。アプリケーションソフトの構成内容はこれだけです。

・index.html
・style.css
・app.js
・indexeddb.min.js

最初は中身は全て真っ白で構いません。拡張子だけきちんと揃えておきましょう。

各構成内容

index.html

todoリストの入力・表示画面を構成するhtmlページです。

今回紹介するコードはいたってシンプルですが、他に必要に応じて様々にタグを追加して構いません。

このWEBページは1つだけでなく、用途に応じて複数作る事ができます。

style.css

通常のCSSファイルです。上記のhtmlファイルの装飾を掛けるファイルです。

app.js

javascriptを記述するファイルです。

indexeddb.min.js

WebSQLの際に経由する「ポリフィル」のコードを入れるファイルになります。

ポリフィル(polyfill)は既にパッケージ化されたコードなので、コピペして貼り付けるだけです。

下の方でポリフィルファイルの実データを紹介しています。

html、css、javascript記述コード

各ファイルのソースコードです。きちんと読込すればファイルの名前を変えても問題はありません。

htmlとcssに関しても必ずしもこの通りにする必要はありません。

自分の好みに合わせて改変してもらって大丈夫です。

index.html内ソース

<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="./styles.css" type="text/css"> </head> <body> <h1>Todoリスト</h1> <form> <input placeholder="ここに入力して下さい"> </form> <ul> </ul> <script src="./indexeddb.min.js"></script> <script src="./app.js"></script> </body> </html>

上記のulタグの間に入力したテキストがliタグで囲まれて挿入されていく事になります(ソース上で確認する事はできませんが)。

表示された項目リストを押せば、リストから消えていきます。

style.css内ソース

h1 { padding: 18px 20px; margin: 0; font-size: 36px; border-bottom: solid 1px #f1f1fd; line-height: 1em; } form { padding: 20px; border-bottom: solid 1px #f1f1fd; } input { width: 100%; padding: 6px; font-size: 1.4em; } ul { margin: 0; padding: 0; list-style: none; } li { padding: 20px; border-bottom: solid 1px #f1f1fd; cursor: pointer; }

indexedDB.min.jsソース

ポリフィルコードが入ったファイルになります。

ポリフィルはこちら

上記コードをまるごとコピーしてindexeddb.min.jsファイル内にペーストして下さい。

中身に関する詳しい説明は割愛させて頂きます。

app.js内ソース

(function() { var db, input, ul; databaseOpen(function() { input = document.querySelector('input'); ul = document.querySelector('ul'); document.body.addEventListener('submit', onSubmit); document.body.addEventListener('click', onClick); databaseTodosGet(renderAllTodos); }); function onClick(e) { if (e.target.hasAttribute('id')) { databaseTodosDelete(parseInt(e.target.getAttribute('id'), 10), function() { databaseTodosGet(renderAllTodos); }); } } function renderAllTodos(todos) { var html = ''; todos.forEach(function(todo) { html += todoToHtml(todo); }); ul.innerHTML = html; } function todoToHtml(todo) { return '
  • '+todo.text+'
  • '; } function onSubmit(e) { e.preventDefault(); databaseTodosAdd(input.value, function() { databaseTodosGet(renderAllTodos); input.value = ''; }); } function databaseOpen(callback) { var version = 1; var request = indexedDB.open('todos', version); request.onupgradeneeded = function(e) { db = e.target.result; e.target.transaction.onerror = databaseError; db.createObjectStore('todo', { keyPath: 'timeStamp' }); }; request.onsuccess = function(e) { db = e.target.result; callback(); }; request.onerror = databaseError; } function databaseError(e) { console.error('An IndexedDB Error has occurred', e); } function databaseTodosAdd(text, callback) { var transaction = db.transaction(['todo'], 'readwrite'); var store = transaction.objectStore('todo'); var request = store.put({ text: text, timeStamp: Date.now() }); transaction.oncomplete = function(e) { callback(); }; request.onerror = databaseError; } function databaseTodosGet(callback) { var transaction = db.transaction(['todo'], 'readonly'); var store = transaction.objectStore('todo'); var keyRange = IDBKeyRange.lowerBound(0); var cursorRequest = store.openCursor(keyRange); var data = []; cursorRequest.onsuccess = function(e) { var result = e.target.result; if (result) { data.push(result.value); result.continue(); } else { callback(data); } }; } function databaseTodosDelete(id, callback) { var transaction = db.transaction(['todo'], 'readwrite'); var store = transaction.objectStore('todo'); var request = store.delete(id); transaction.oncomplete = function(e) { callback(); }; request.onerror = databaseError; } }());

    app.js(javascript)内の簡単な解説

    2つのテーブルを作成

    IndexedDBデータベースには、複数のテーブルを作成する事ができます。

    これらのテーブルは「objectStores」と呼ばれます。

    今回の手順では、「todo」という名前のobjectStoresを作成しています。

    todoアイテムを格納するデータ形式は、次の2つのフィールドプロパティを持ちます。

    ・timeStamp…分類と削除キーとして機能
    ・text…ユーザーが入力したテキスト

    アイテム追加

    入力されたデータをtodoテーブルに追加します。

    submitイベントが起きた時にinput要素の値を呼び出し、databaseTodosAddで項目がテーブルに正常に追加されたら、input要素の値を空にします。

    databaseTodosAdd関数は、タイムスタンプとともにローカルデータベースにタスク項目を保存し、次にcallbackを実行する関数です。

    アイテムの取得

    次に、追加されたデータをテーブルから取得します。

    各アイテムがオブジェクトストアから全て取得された後にcallbackが呼び出されます。

    dataという名前の配列に入れ、すべての項目を取得し終わるとcallbackでその配列を呼び出す仕組みです。

    アイテムの表示

    todoアイテムを表示するためにあるのが、2つの関数です。

    ・todoToHtml…todoオブジェクトを取得
    ・renderAllTodos…todoオブジェクトの配列を受け取り、それらをHTML文字列に変換してinnerHTMLに設定

    アプリケーションソフトが新しいアイテムをデータから受け取った後は、常に更新してアイテムが表示されるようにします。

    新しいアイテムの表示

    databaseTodosGet(renderAllTodos);

    アイテムを追加する度、データベースから全てのアイテムを再度取得して画面に表示する命令です。

    アイテムの削除

    本サンプルでは、ユーザーは項目自体をクリックすると削除ができるようにしています。

    各アイテムについたtimeStampに設定されたIDを与える事で、bodyに追加されたクリックイベントリスナーが有効になります。

    onClickクリックイベントで、ターゲット要素にID属性があるかどうかをチェックします。

    ID属性がある場合は、それを整数に戻しその値をparseIntで呼び出して、databaseTodosDeleteで削除します。

    アイテムが正常に削除された場合は、todoリストを更新するという流れです。

    実際のアプリケーションでは、ユーザーが誤って項目をクリックして削除しないよう、専用の「削除」ボタンまたはダイアログを表示した方が良いでしょう。

    PCソフト「todoリスト」サンプル例

    実際のPCソフトサンプル例をアップしております。

    todoリストアプリケーションサンプル例はこちら

    本来はこのようにWEB上にUPしなくても、ローカル環境でPCソフトの様に動きます。

    ネット回線が切れている場合

    ここまでオフラインによるアプリ作成を紹介しました。

    確かにデータをオフラインで保存できるようにはなっていますが、実は完全な状態ではありません。

    PCのインターネット回線が完全に切れている状態で使おうとすると、アプリケーション自体が開きません。

    オフラインとはインターネットにつながっていない状態なのですから、この状態でもアプリケーションが利用できる必要があります。

    これを修正するには、HTML5アプリケーションキャッシュを使用します。

    manifest属性の追加

    アプリケーションキャッシュを有効にするためには、WEBページのhtmlタグに「manifest属性」を追加します。

    <!DOCTYPE html> <html manifest="./offline.appcache"> 以下は同じ

    次にここで読み込むマニフェストファイルを作成します。

    これはオフラインで使用できるようにするファイルと、キャッシュの動作を大まかに指定するテキストファイルです。

    .appcacheファイルについて

    .appcacheという拡張子になっていますので、一旦は.txtなどメモ帳で開きやすいファイルにしましょう。

    中身を記述したあとに拡張子を.appcacheに変更すれば良いと思います。

    マニフェストファイル内記述

    CACHE MANIFEST ./style.css ./indexeddb.min.js ./app.js NETWORK: *

    CACHE MANIFESTセクション

    CACHE MANIFESTで始まるセクションは、ブラウザに次の指示をしています。

    ・アプリケーションが最初にアクセスされた時、下の各ファイルをダウンロードし、アプリケーションキャッシュに保存する
    ・以降下のファイルのいずれかが必要になった場合、インターネットから再ダウンロードはせず、ファイルのキャッシュをロードする。

    NETWORKセクション

    NETWORKセクションは、他の全てのファイルが必要になるたびにインターネットから新しくダウンロードする必要があるファイルを指定しています。

    まとめ

    以上、IndexedDBとWebSQL(ポリフィル経由)の両方を採用する事でオフラインで動作するtodoリストができました。

    主要ブラウザで実行でき、簡単で高速なPCソフトとなっています。

    最後に紹介したmanifestファイルですが、これはPCを完全なオフラインにした場合に使うファイルとして紹介しました。

    実際には回線まで完全に切る事はほとんど無いと言えますので、完全にオフラインにしないのであればこのmanifestファイルは準備する必要はありません。

    このmanifestファイルが無くてもブラウザ上でtodoリストはきちんと動きます。

    この記事をシェアする

    一押し人気コーナー紹介

    HTMLカテゴリの関連記事