====== Titanium Mobileに神の火を! - Prometheus.js ====== コメントと更新履歴は[[http://0-oo.net/log/category/javascript/prometheus/|Prometheus Archive - ゼロと無限の間のログ]]でどうぞ。 {{:javascript:fire_beiz.jp_s05820.jpg?nolink&|}} iPhoneアプリもAndroidアプリもJavaScriptで作れてしまう[[http://www.appcelerator.com/products/titanium-mobile-application-development/|Titanium Mobile]]。便利なのだがその構成は良くも悪くもきちんと体系だっている。(JavaやYUIを連想させる?) そこで、もう少しだけ手軽にTitamium Mobileを使えるように、Titaniumをラップするライブラリを作ってみた。その名も、**Prometheus.js**。 ===== ライセンス ===== MITライセンス ===== 使用例 ===== ==== UIを生成する ==== === 全てのUIを、本家Titaniumよりちょっと短いコードで生成できる === // Titaniumの場合 var win = Ti.UI.createWindow(); // Prometheus.jsの場合 var win = Pr.window(); === UI生成時のパラメータはTitaniumと同様に渡すことができる === var label = Pr.label({text:"ラベルだよ", fontWeight:"bold"}); === ラベルとボタンは、パラメータが表示文字列のみなら、それを文字列として渡すことができる === Hashにしない分、ちょっと短くて済む // Titaniumの場合 var label = Ti.UI.createLabel({text:"ラベルだよ"}); // Prometheus.jsの場合 var label = Pr.label("ラベルだよ"); === ボタンやダイアログは、第2匹数としてonclickのイベントハンドラーを渡すことができる === // Titaniumの場合 var button = Ti.UI.creatButton({title:"押してみる?"}); button.addEventListener("click", function() { alert("押しちゃったね"); }); // Prometheus.jsの場合 var button = Pr.button("押してみる?", function() { alert("押しちゃったね"); }); === Viewは第2匹数としてView上に載せるUIを渡すことができる === var view = Pr.view({}, Pr.label("viewに載るよ")); // 複数の場合は配列で渡す var view = Pr.view({}, [Pr.label("ラベル1"), Pr.label("ラベル2")]); === パラメータの共通の初期値を指定できる === 見た目のデザイン等を後から一括して変えたい時に便利 // ラベルは全て太字にする場合 Pr.params.label.fontWeight = "bold"; この後にPrometheus.jsで生成したlabelは全てfontWeightがboldになる また、いくつかのUIはデフォルトで使いやすいように初期値が設定されている === これらを合わせると、Titaniumに比べてこれぐらいコードが短くなる === // Titaniumの場合 var win = Ti.UI.createWindow({backgroundColor:"#000", layout:"vertical"}); var view = Ti.UI.createView({layout:"horizontal"}); win.add(view); view.add(Ti.UI.createLabel({text:"ラベル1", fontWeight:"bold"})); view.add(Ti.UI.createLabel({text:"ラベル2", fontWeight:"bold"})); var button = Ti.UI.createButton({title:"ボタン"}); button.addEventListener("click", function() { Ti.UI.createAlertDialog(message:"こんにちはこんにちは!", buttonNames:["OK"]).show(); }); win.add(button); // Prometheus.jsの場合 var win = Pr.win(); Pr.params.label.fontWeight = "bold"; win.add(Pr.view({}, [Pr.label("ラベル1"), Pr.label("ラベル2")]); win.add(Pr.button("ボタン", function() { pr.alertDialog(message:"こんにちはこんにちは!").show(); })); ==== DBにアクセスする ==== ローカルのSQLiteに簡単にアクセスできる\\ DatabaseやResultsetのclose()もしてくれるので楽ちん var db = Pr.db("dbName"); // テーブル生成(該当のテーブルが既にある場合は無視される) db.table("people(id INTEGER, name TEXT, email TEXT)"); // SELECT(パラメータは、取得列、テーブル名、取得条件、その他) var rows = db.select("id, name", "people", { name: "Taro", email: "taro@example.com" }, "ORDER BY id"); // 戻り値はResultsetオブジェクトではなく配列なので扱いやすい for (var i = 0; i < rows; i++) { var id = rows[i]["id"]; } // INSERT(パラメータは、テーブル名、登録データ。戻り値は(あれば)連番のキー値) var id = db.insert("poeple", { id: 1, name: "Taro" }); // UPDATE(パラメータは、テーブル名、更新値、更新条件。戻り値は更新レコード数) var count = db.update("people", { name: "Jiro", email: "jiro@example.com" }, { id: 2, name: "Taro" }); // DELETE(パラメータは、テーブル名、削除条件。戻り値は削除レコード数) var count = db.remove("people", { id: 2, name: "Taro" }); // メソッド名が"delete"でないので注意! // その他のSQLを実行したい場合はTi.Database#execute()と同様に var results = db.execute(sql, params); while(rows.isValidRow()){ var something = rows.field(0); // 略 rows.next(); } // この場合は勝手にclose()してくれないので注意 results.close(); ==== HTTPで通信する ==== Ti.Network.createHTTPClientによる一連の処理のショートカット Pr.http("POST", "http://www.example.com/", {q:"hoge"}, function(json) { // サーバからのレスポンスのJSONをHash化したものが渡される }); JSONにしたくない場合は、第6引数で"TEXT"を指定すればよい ==== ディスプレイのサイズを取得する ==== var w = Pr.width(); var h = Pr.height(); ===== ソースコード ===== Promethus.jsを使いたい場合は(ダウンロードできるファイルを用意してないので)下記のソースコードをコピーして使ってください /** * Prometheus.js - The library for Titanium Mobile * * @see http://0-oo.net/sbox/javascript/prometheus * @version 0.2.0 * @copyright 2012 dgbadmin@gmail.com * @license http://0-oo.net/pryn/MIT_license.txt (The MIT license) * * See also the references of Titanium Mobile * @see http://tidocs.com/mobile/latest/ * @see http://code.google.com/p/titanium-mobile-doc-ja/wiki/toc */ var Prometheus = {}; var Pr = Prometheus; Ti.UI.setBackgroundColor('#000'); /************************************************* * The wrapper object of Ti.Database ************************************************/ /** * Get a wrapper of a database * @param String dbName * @return Object */ Pr.db = function(dbName) { var wrapper = {dbName:dbName, db:null}; /** * Execute SQL (It is the wrapper of Ti.Database.execute()) * @param String sql * @param Object (Optional) value(s) of place holder(s) * @return Object Ti.Database.Resultset or something Ti.Database.execute() returns */ wrapper.execute = function() { if (!this.db) { this.db = Ti.Database.open(this.dbName); this.db.execute.apply = Function.prototype.apply; } return this.db.execute.apply(this.db, arguments); }; /** * Close the database */ wrapper.close = function() { this.db.close(); this.db = null; }; /** * Create a table, if it does not exist * @param String sql SQL to create a table */ wrapper.table = function(sql) { this.execute('CREATE TABLE IF NOT EXISTS ' + sql); this.close(); }; /** * Select columns * @param String columns Columns to select * @param String from Name of a table * @param Hash where (Optional) Conditions to select * @param String ohters (Optional) SQL after WHERE * @return Array Results */ wrapper.select = function(columns, from, where, others) { var params = this._where(where || {}); params[0] = "SELECT " + columns + " FROM " + from + params[0] + " " + (others || ""); var arr = this.rows2arr(this.execute.apply(this, params)); this.close(); return arr; }; /** * Insert a row * @param String table Name of a table * @param Hash values Values to insert * @return Number ID of the last inserted row */ wrapper.insert = function(table, values) { var cols = []; var vals = []; var params = [""]; for (var col in values) { cols.push(col); vals.push("?"); params.push(values[col]); } params[0] = "INSERT INTO " + table + "(" + cols.join(",") + ") VALUES(" + vals.join(",") + ")"; this.execute.apply(this, params); var rowId = this.db.lastInsertRowId; this.close(); return rowId; }; /** * Update colulmns * @param String table Name of a table * @param Hash set Values to update * @param Hash where (Optional) Conditions to update * @return Number the number of the updated rows */ wrapper.update = function(table, set, where) { var sets = []; var params = [""]; for (var col in set) { sets.push(col + " = ?"); params.push(set[col]); } var cond = this._where(where || {}); params[0] = "UPDATE " + table + " SET " + sets.join(",") + cond.shift(); this.execute.apply(this, params.concat(cond)); var affected = this.db.rowsAffected; this.close(); return affected; }; /** * Delete rows * @param String table Name of a table * @param Hash where (Optional) Conditions to delete * @return Number The number of the deleted rows */ wrapper.remove = function(table, where) { var params = this._where(where || {}); params[0] = "DELETE FROM " + table + params[0]; this.execute.apply(this, params); var affected = this.db.rowsAffected; this.close(); return affected; }; /** * Build a SQL of "WHERE" * @param Hash hash * @return Array SQL and values of placeholders */ wrapper._where = function(hash) { var sql = []; var arr = [""]; for (var key in hash) { sql.push(key + " = ?"); arr.push(hash[key]); } if (sql.length) { arr[0] = " WHERE " + sql.join(" AND "); } return arr; }; /** * Convert a Ti.Database.Resultset to an array */ wrapper.rows2arr = function(rows) { var arr = []; while(rows.isValidRow()){ var row = {} for (var i = 0, cnt = rows.fieldCount; i < cnt; i++) { row[rows.fieldName(i)] = rows.field(i); } arr.push(row); rows.next(); } rows.close(); return arr; }; return wrapper; }; /************************************************* * The utility functions ************************************************/ /** * Send a HTTP request and get a response * @param String httpMethod "GET" or "POST" * @param String url * @param Hash params * @param Function onload * @param Function onerror (Optioanl) * @param String format (Optioanl) "TEXT" or "JSON"(default) */ Pr.http = function(httpMethod, url, params, onload, onerror, format) { var http = Ti.Network.createHTTPClient({ onload: function() { var res; switch (format) { case "TEXT": res = this.responseText; default: res = JSON.parse(this.responseText); } onload(res); }, onerror: onerror || function(error){ Pr.alertDialog({title:"Error", message:error}).show(); } }); http.open(httpMethod, url); http.send(params || {}); }; /** * Get width of the display * @return Number */ Pr.width = function() { return Ti.Platform.displayCaps.platformWidth; }; /** * Get height of the display * @return Number */ Pr.height = function() { return Ti.Platform.displayCaps.platformHeight; }; /** * Merge hashes * @param Hash data1 * @param Hash data2 * @return Hash */ Pr.merge = function(data1, data2) { var dst = {}; if (data1) { for (var i in data1) { dst[i] = data1[i]; } } if (data2) { for (var j in data2) { dst[j] = data2[j]; } } return dst; }; /** * Add a click listener * @param Object obj * @param Function onclick * @return Object */ Pr.clickable = function(obj, onclick) { if (onclick) { obj.addEventListener("click", onclick); } return obj; }; /************************************************* * The default parameters of UIs ************************************************/ Pr.params = { ui2DMatrix: {}, // With the prefix "ui" ui3DMatrix: {}, // With the prefix "ui" activityIndicator:{}, alertDialog:{buttonNames:["OK"]}, animation:{}, button:{}, buttonBar:{}, coverFlowView:{}, dashboardItem:{}, dashboardView:{}, emailDialog:{}, imageView:{}, label:{}, optionDialog:{}, picker:{}, pickerColumn:{}, pickerRow:{}, progressBar:{}, scrollView:{}, scrollableView:{}, searchBar:{}, slider:{}, uiSwitch:{}, // With the prefix "ui" tab:{}, tabGroup:{}, tabbedBar:{}, tableView:{}, tableViewRow:{}, tableViewSection:{}, textArea:{}, textField:{passwordMask:false}, toolbar:{}, view:{layout:"horizontal"}, // "vertical" or "horizontal" or false webView:{backgroundColor:"#000"}, window:{backgroundColor:"#000", layout:"vertical"} }; /************************************************* * The creaters of UIs ************************************************/ /** * Create a 2dMatrix * @param Hash params * @return Object */ Pr.ui2DMatrix = function(params) { return Ti.UI.create2DMatrix(Pr.merge(Pr.params.ui2DMatrix, params)); }; /** * Create a ui3DMatrix * @param Hash params * @return Object */ Pr.ui3DMatrix = function(params) { return Ti.UI.create3DMatrix(Pr.merge(Pr.params.ui3DMatrix, params)); }; /** * Create an activityIndicator * @param Hash params * @return Object */ Pr.activityIndicator = function(params) { return Ti.UI.createActivityIndicator(Pr.merge(Pr.params.activityIndicator, params)); }; /** * Create an alertDialog * @param Hash params * @param Function onclick (Optional) * @return Object */ Pr.alertDialog = function(params, onclick) { return Pr.clickable(Ti.UI.createAlertDialog(Pr.merge(Pr.params.alertDialog, params)), onclick); }; /** * Create an animation * @param Hash params * @return Object */ Pr.animation = function(params) { return Ti.UI.createAnimation(Pr.merge(Pr.params.animation, params)); }; /** * Create a button * @param Hash params * @param Function onclick (Optional) * @return Object */ Pr.button = function(params, onclick) { if (typeof(params) == "string") { params = {title:params}; } return Pr.clickable(Ti.UI.createButton(Pr.merge(Pr.params.button, params)), onclick); }; /** * Create a buttonBar * @param Hash params * @return Object */ Pr.buttonBar = function(params) { return Ti.UI.createButtonBar(Pr.merge(Pr.params.buttonBar, params)); }; /** * Create a coverFlowView * @param Hash params * @return Object */ Pr.coverFlowView = function(params) { return Ti.UI.createCoverFlowView(Pr.merge(Pr.params.coverFlowView, params)); }; /** * Create a dashboardItem * @param Hash params * @return Object */ Pr.dashboardItem = function(params) { return Ti.UI.createDashboardItem(Pr.merge(Pr.params.dashboardItem, params)); }; /** * Create a dashboardView * @param Hash params * @return Object */ Pr.dashboardView = function(params) { return Ti.UI.createDashboardView(Pr.merge(Pr.params.dashboardView, params)); }; /** * Create an emailDialog * @param Hash params * @return Object */ Pr.emailDialog = function(params) { return Ti.UI.createEmailDialog(Pr.merge(Pr.params.emailDialog, params)); }; /** * Create an imageView * @param Hash params * @return Object */ Pr.imageView = function(params) { return Ti.UI.createImageView(Pr.merge(Pr.params.imageView, params)); }; /** * Create a label * @param Hash params * @return Object */ Pr.label = function(params) { if (typeof(params) == "string") { params = {text:params}; } return Ti.UI.createLabel(Pr.merge(Pr.params.label, params)); }; /** * Create a optionDialog * @param Hash params * @param Function onclick (Optional) * @return Object */ Pr.optionDialog = function(params, onclick) { return Pr.clickable(Ti.UI.createOptionDialog(Pr.merge(Pr.params.optionDialog, params)), onclick); }; /** * Create a picker * @param Hash params * @return Object */ Pr.picker = function(params) { return Ti.UI.createPicker(Pr.merge(Pr.params.picker, params)); }; /** * Create a pickerColumn * @param Hash params * @return Object */ Pr.pickerColumn = function(params) { return Ti.UI.createPickerColumn(Pr.merge(Pr.params.pickerColumn, params)); }; /** * Create a pickerRow * @param Hash params * @return Object */ Pr.pickerRow = function(params) { return Ti.UI.createPickerRow(Pr.merge(Pr.params.pickerRow, params)); }; /** * Create a progressBar * @param Hash params * @return Object */ Pr.progressBar = function(params) { return Ti.UI.createProgressBar(Pr.merge(Pr.params.progressBar, params)); }; /** * Create a scrollView * @param Hash params * @return Object */ Pr.scrollView = function(params) { return Ti.UI.createScrollView(Pr.merge(Pr.params.scrollView, params)); }; /** * Create a scrollableView * @param Hash params * @return Object */ Pr.scrollableView = function(params) { return Ti.UI.createScrollableView(Pr.merge(Pr.params.scrollableView, params)); }; /** * Create a searchBar * @param Hash params * @return Object */ Pr.searchBar = function(params) { return Ti.UI.createSearchBar(Pr.merge(Pr.params.searchBar, params)); }; /** * Create a slider * @param Hash params * @return Object */ Pr.slider = function(params) { return Ti.UI.createSlider(Pr.merge(Pr.params.slider, params)); }; /** * Create a uiSwitch * @param Hash params * @return Object */ Pr.uiSwitch = function(params) { return Ti.UI.createSwitch(Pr.merge(Pr.params.uiSwitch, params)); }; /** * Create a tab * @param Hash params * @return Object */ Pr.tab = function(params) { return Ti.UI.createTab(Pr.merge(Pr.params.tab, params)); }; /** * Create a tabGroup * @param Hash params * @return Object */ Pr.tabGroup = function(params) { return Ti.UI.createTabGroup(Pr.merge(Pr.params.tabGroup, params)); }; /** * Create a tabbedBar * @param Hash params * @return Object */ Pr.tabbedBar = function(params) { return Ti.UI.createTabbedBar(Pr.merge(Pr.params.tabbedBar, params)); }; /** * Create a tableView * @param Hash params * @return Object */ Pr.tableView = function(params) { return Ti.UI.createTableView(Pr.merge(Pr.params.tableView, params)); }; /** * Create a tableViewRow * @param Hash params * @return Object */ Pr.tableViewRow = function(params) { return Ti.UI.createTableViewRow(Pr.merge(Pr.params.tableViewRow, params)); }; /** * Create a tableViewSection * @param Hash params * @return Object */ Pr.tableViewSection = function(params) { return Ti.UI.createTableViewSection(Pr.merge(Pr.params.tableViewSection, params)); }; /** * Create a textArea * @param Hash params * @return Object */ Pr.textArea = function(params) { return Ti.UI.createTextArea(Pr.merge(Pr.params.textArea, params)); }; /** * Create a textField * @param Hash params * @return Object */ Pr.textField = function(params) { return Ti.UI.createTextField(Pr.merge(Pr.params.textField, params)); }; /** * Create a toolbar * @param Hash params * @return Object */ Pr.toolbar = function(params) { return Ti.UI.createToolbar(Pr.merge(Pr.params.toolbar, params)); }; /** * Create a view * @param Hash params * @param Object or Array children (Optional) Children of a webView * @return Object */ Pr.view = function(params, children) { var view = Ti.UI.createView(Pr.merge(Pr.params.view, params)); if (children) { if (children instanceof Array) { for (var i = 0; i < children.length; i++) { view.add(children[i]); } } else { view.add(children); } } return view; }; /** * Create a webView * @param Hash params * @return Object */ Pr.webView = function(params) { return Ti.UI.createWebView(Pr.merge(Pr.params.webView, params)); }; /** * Create a window * @param Hash params * @return Object */ Pr.window = function(params) { return Ti.UI.createWindow(Pr.merge(Pr.params.window, params)); };