- nw.jsをインストールする
- NW.jsでのアプリケーションの構築と実行
- ネイティブコントロールの操作の基本(メニューの作成など)
この記事では、パスワードを保存するためのアプリケーションの作成を検討します。 アプリケーションは比較的単純で、ほとんどの部分は実際のプロトタイプです。 ただし、必要に応じて時間がある場合は、変更して日常業務に完全に使用できます。
パスワード保存アプリケーションの基礎
ご存知のように、開発は純粋なJavaScriptとさまざまなフレームワークの両方を使用して実行できますが、その多くは非常に多く、その種類に迷うことがあり、長い間選択することができません 。 アプリケーション開発では、パターンが特に人気があり、その名前はMVで始まります( MVC 、 MVVM 、 MVP )。 同様のパターンを使用するフレームワークの1つは、アプリケーションを開発するときに使用するAngular JSです。 それに慣れていない場合は、ドキュメント( チュートリアル 、 API )を読むことをお勧めします。ロシア語のマニュアルで基本情報を学ぶこともできます。
アプリケーションは何になりますか? すべてのデータはテーブルに表示され、ログインが表示され、パスワードの代わりにアスタリスクが表示されます。 ユーザーは、新しいログイン/パスワードを追加したり、不要になったエントリを削除したりできます。 さらに、編集を提供する必要があります。
アプリケーションの基本機能を実装します。 これを行うには、ソースコードを見つけるフォルダーを作成し、その中にpackage.jsonも配置します(これを行う方法については、パート1を参照してください)。
次のディレクトリで構成される基本的なフォルダー構造を作成します。
- CSS-このフォルダーにスタイルを配置します(メインのスタイルを含むindex.cssファイルをここに追加します)
- コントローラー -ここがコントローラーになります
- ビュー - ビューのフォルダー
- ディレクティブ - ディレクティブのあるフォルダー
- Lib-ライブラリ( angle.min.jsをこのフォルダにコピーする必要があります。angularJSの 追加方法について)
さらに、 index.htmlファイルをプロジェクトルートに追加します。これは、アプリケーションへのエントリポイントになります。 基本的なマークアップを作成します。
基本的なマークアップ
<html ng-app="main"> <head> <meta charset="utf-8"> <title>Password keeper</title> <link rel="stylesheet" type="text/css" href="css/index.css"> </head> <body> <table> <thead> <tr> <td></td> <td>Login</td> <td>Password</td> <td></td> </tr> </thead> <tbody> <tr> <td></td> <td></td> <td></td> <td><a></a></td> </tr> </tbody> <tfoot> <tr> <td></td> <td><a></a></td> <td></td> <td></td> </tr> </tfoot> </table> <script type="text/javascript" src="lib/angular.min.js"></script> </body> </html>
アプリケーションは非常にシンプルであるため、コントローラーを作成し、その中にアプリケーションのすべてのメインロジックを配置します(ロジックが大きくなるにつれて、 Serviceフォルダーを追加し、その中にサービスを配置する必要があります。 「薄い」)。 コントローラーをmain 、コントローラーファイルをmain.ctrl.jsと呼びます。 したがって、コントローラーのブランク:
(function () { 'use strict'; angular .module('main', []) .controller('MainCtrl', [MainCtrl]); function MainCtrl() { this.data = []; return this; } })();
プロトタイプのユーザー名/パスワードを含むデータは、 データ配列に配置されます 。 編集の実装を簡素化するには、独自のEditableText要素を作成し、ディレクティブとして配置します。 この要素は次のように機能します。要素はテキストとして表示され、要素をクリックするとテキストがテキスト入力フィールドに変わり、フォーカスが失われると要素がテキストとして再び表示されます。 これを行うには、 Viewフォルダー内にeditableText.htmlディレクティブのマークアップファイルを作成します。
<input ng-model="value"> <span ng-click="edit()">{{value}}</span>
そして、 ディレクティブフォルダー内で、 editableText.jsファイルを作成します。
編集可能なテキストディレクティブコード
(function () { 'use strict'; angular .module('main') .directive('editableText', [editableText]); function editableText() { var directive = { restrict: 'E', scope: { value: "=" }, templateUrl: 'view/editableText.html', link: function ( $scope, element, attrs ) { // input var inputElement = angular.element( element.children()[0] ); element.addClass( 'editable-text' ); // , , // $scope.edit = function () { element.addClass( 'active' ); inputElement[0].focus(); }; // , .. inputElement.prop( 'onblur', function() { element.removeClass( 'active' ); }); } }; return directive; } })();
このディレクティブには、 index.css内に配置できるいくつかのスタイルも必要です 。
.editable-text span { cursor: pointer; } .editable-text input { display: none; } .editable-text.active span { display: none; } .editable-text.active input { display: inline-block; }
ディレクティブの使用方法は次のとおりです。
<editable-text value="variable"></editable-text>
ログインの場合、すべてが順調です。テキストまたはテキストフィールドのいずれかを表示しますが、パスワードは表示すべきではありません。 次のように、暗号フィールドをディレクティブのスコープに追加します。
scope: { value: "=", crypto: "=" }
また、ディレクティブのマークアップも変更します。
<input ng-model="value"> <span ng-click="edit()">{{crypto?'***':value}}</span>
さらに、index.htmlにスクリプトを追加することを忘れないでください:
<script type="text/javascript" src="lib/angular.min.js"></script> <script type="text/javascript" src="controller/main.ctrl.js"></script> <script type="text/javascript" src="directive/editableText.js"></script>
機能を追加します。 次のようにコントローラーを変更します。
コントローラーコード
function MainCtrl() { var self = this; this.data = []; this.remove = remove; this.copy = copy; this.add = add; return this; function remove(ind){ self.data.splice(ind, 1); }; function copy(ind){ // }; function add(){ self.data.push({login: "login", password: "password"}); }; }
さらに、マークアップの変更が必要です。
最終マークアップ
<body ng-controller="MainCtrl as ctrl"> <table> <thead> <tr> <td></td> <td>Login</td> <td>Password</td> <td></td> </tr> </thead> <tbody> <tr ng-repeat="record in ctrl.data track by $index"> <td><a ng-click="ctrl.copy($index)">{{$index}}</a></td> <td><editable-text value="record.login"></editable-text></td> <td><editable-text value="record.password" crypto="true"></editable-text></td> <td><a ng-click="ctrl.remove($index)"></a></td> </tr> </tbody> <tfoot> <tr> <td></td> <td><a ng-click="ctrl.add()"></a></td> <td></td> <td></td> </tr> </tfoot> </table> <script type="text/javascript" src="lib/angular.min.js"></script> <script type="text/javascript" src="controller/main.ctrl.js"></script> <script type="text/javascript" src="directive/editableText.js"></script> </body>
この段階で、スタイリングを行うことができます。 単純なスタイルの例( index.cssにスタイルを追加しますが、スタイルが多数ある場合は、スタイルをファイルに分割したり、 LESSなどのプリプロセッサを使用することもできます):
アプリケーションスタイリングの例
table { border-collapse: collapse; margin: auto; width: calc(100% - 40px); } table, table thead, table tfoot, table tbody tr td:first-child, table tbody tr td:nth-child(2), table tbody tr td:nth-child(3), table thead tr td:nth-child(2), table thead tr td:nth-child(3) { border: 1px solid #000; } table td { padding: 5px; } table thead { background: #EEE; } table tbody tr td:first-child { background: #CCC; } table tbody tr td:nth-child(2) { background: #777; color: #FFF; } table tbody tr td:nth-child(3) { background: #555; color: #FFF; } table thead tr td:nth-child(2),table thead tr td:nth-child(3) { text-align: center; } table a { font-size: smaller; cursor: pointer; }
アプリケーションは次のとおりです。
クリップボードを操作する
そのため、アプリケーションの基礎は用意されていますが、主な目的をまだ実装していません。パスワードをコピーすることはできません(むしろ、コピーすることはできますが、非常に不便です)。 開始するには、NW.jsでクリップボードを操作することを検討してください
クリップボードという特別なオブジェクトがあります 。これは、 WindowsのクリップボードとGTKの抽象化として、またペーストボード(Mac)の抽象化として使用されます。 執筆時点では、テキストのみの書き込みと読み取りのサポートがあります。
オブジェクトを操作するには、使い慣れたnw.guiモジュールが必要です。
var gui = require('nw.gui'); var clipboard = gui.Clipboard.get();
独自のオブジェクトを作成することはできず、システムオブジェクトのみを取得できることに注意してください。 次の3つの方法がサポートされています。
- get ([type])-このオブジェクトのタイプを示すクリップボードからオブジェクトを取得します。デフォルトはtextですが、これまでのところ、これがサポートされている唯一のタイプです
- set (data、[type])-オブジェクトをクリップボードに送信します(タイプのみ-「テキスト」もサポートされます)
- clear-クリップボードを消去します
これで、アプリケーションの機能を終了でき、コントローラーは次のようになります。
コントローラーコード
function MainCtrl() { var self = this; var gui = require('nw.gui'); var clipboard = gui.Clipboard.get(); this.data = []; this.remove = remove; this.copy = copy; this.add = add; return this; function remove(ind){ self.data.splice(ind, 1); }; function copy(ind){ clipboard.set(self.data[ind].password); }; function add(){ self.data.push({login: "login", password: "password"}); }; }
パスワード保存
アプリケーションの起動後、ユーザーはいくつかのパスワードを保存し、アプリケーションを閉じました。 翌日、パスワードがなくなったことがわかりました。 問題は、それらを閉じるときに削除された通常のローカル変数に保存したことです。
3番目の部分では、NW.jsがデータベースでどのように機能するかを見ていきますが、今のところはlocalStorageにパスワードを保存します 。 機能の作成を開始する前に(使用しているアプリケーションは単なるプロトタイプですが)、セキュリティに注意する必要があります。 これを行うには、パスワードを平文で保存しないでください。
暗号化/復号化用のさまざまなJavaScriptライブラリがあります。 そのようなライブラリの1つにcrypto-jsがあります。 node.jsのモジュールとしてインストールします。 ライブラリは多数の標準をサポートしており、その完全なリストはドキュメントに記載されています。 同時に、すべてのモジュールと個別のモジュールの両方を接続できます。
// , CryptoJS.HmacSHA1 var CryptoJS = require("crypto-js"); // , AES var AES = require("crypto-js/aes");
メッセージを暗号化するには、暗号化方式が使用されます。
var ciphertext = CryptoJS.AES.encrypt('', ' ');
復号化はもう少し複雑です:
var bytes = CryptoJS.AES.decrypt(ciphertext.toString(), ' '); var plaintext = bytes.toString(CryptoJS.enc.Utf8);
アプリケーションを変更して、アプリケーションを閉じるときにパスワードを保存し、起動時にロードできるようにします。
crypto.svcサービスを作成し、 サービスフォルダーに配置します(このフォルダーをまだ作成していない場合は、アプリケーションルートに作成します)。
サービスコード
(function () { 'use strict'; angular .module('main') .factory('CryptoService', [CryptoService]); function CryptoService() { var CryptoJS = require("crypto-js"); var secretKey = "secretKey"; var service = { encrypt: encrypt, decrypt: decrypt }; return service; function encrypt(data) { return CryptoJS.AES.encrypt(JSON.stringify(data), secretKey); } function decrypt(text) { var bytes = CryptoJS.AES.decrypt(text.toString(), secretKey); var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); return decryptedData; } } })();
サービスを使用するには、コントローラーをアップグレードします。
コントローラーコード
(function () { 'use strict'; angular .module('main', []) .controller('MainCtrl', ['$scope', 'CryptoService', MainCtrl]); function MainCtrl($scope, CryptoService) { var self = this; var gui = require('nw.gui'); var clipboard = gui.Clipboard.get(); var localStorageKey = "loginPasswordData" this.data = []; this.remove = remove; this.copy = copy; this.add = add; load(); $scope.$watch("ctrl.data", save, true); return this; function remove(ind){ self.data.splice(ind, 1); }; function copy(ind){ clipboard.set(self.data[ind].password); }; function add(){ self.data.push({login: "login", password: "password"}); }; function load(){ var text = localStorage.getItem(localStorageKey); if(text) { self.data = CryptoService.decrypt(text); } } function save(){ if(self.data) { localStorage.setItem(localStorageKey, CryptoService.encrypt(self.data)); } } } })();
サービスの接続に加えて、 AngularJSに既に存在する$ scopeサービスも必要でした。 $ watchメソッドを使用して、データが変更された瞬間を追跡し、それらを時間内に保存します(3番目の引数がtrueであるため、変更は配列だけでなく、挿入/削除だけでなく、変更も追跡されます配列要素、つまり個々の配列要素のユーザー名またはパスワードの変更)。 ビューを開くと、データの読み込みが行われます。
トレイに向ける
アプリケーションの基礎は用意されていますが、ご存知のように、このようなプログラムはシステムトレイに最小化されているため、多くの開いているウィンドウでユーザーが過負荷にならないようになっています。
NW.jsに導入されたもう1つの抽象化は、トレイです。Windowsのシステムトレイ アイコン 、GTKのステータスアイコン 、OSXのステータスアイテム 。 このオブジェクトは、既知のguiモジュールを使用して作成されます。
var gui = require("nw.gui"); var tray = new gui.Tray({ title: 'Tray', icon: 'img/icon.png' });
このオブジェクトを操作するときは、変数のスコープに注意する必要があります。関数内で変数を作成すると、 GCによってすぐに削除されます。 オブジェクトを作成するとき、例で行ったように、すぐにプロパティを作成できます。または、少し後でこれを処理できます。 このオブジェクトには、次のプロパティを定義できます。
- タイトル -Mac OSXでのみ表示されます
- ツールチップ -すべてのプラットフォームで利用可能なツールチップ
- アイコン -トレイに表示されるアイコンは、すべてのプラットフォームでも利用可能です
- メニュー -Mac OS Xのクリックで表示されるメニュー(WindowsおよびLinux用)-シングルクリックおよび右クリックに応答します(メニューの作成方法については、シリーズの最初の部分を参照してください)
アプリケーションでトレイを使用するには、マークアップ要素を作成する必要があります 。最も明白なオプションはボタンbuttonです。 次に、 クリックイベントをサブスクライブし、 windowオブジェクトのメソッドを使用する必要があります。これについては、これから説明します。
ウィンドウでの作業
ウィンドウを操作するには、既存のウィンドウを取得するか、新しいウィンドウを作成する必要があります。 したがって、アプリケーションが表示されている現在のウィンドウを取得するには、次のコマンドを実行する必要があります。
var win = gui.Window.get();
そして、新しいウィンドウを作成するには、ページが配置されているアドレス、このウィンドウで開くアドレス、および開くためのパラメーターを指定する必要があります(これらのパラメーターは、マニフェストの作成時に指定したものに対応します。一連の記事の最初の部分を参照)。
var win = gui.Window.open ('https://myurl', { position: 'center', width: 901, height: 127 });
パラメータに特別なプロパティフォーカスを渡すこともできます。trueを指定すると、新しく作成されたウィンドウはすぐにフォーカスを受け取ります。そうでない場合、フォーカスは現在のウィンドウに残ります。
新しいウィンドウを作成し、作成後にそれを使用したい場合は、対応するイベントにサブスクライブする必要があります。
win.on ('loaded', function(){ // document , var document = win.window.document; // ... });
この例からわかるように、ウィンドウのプロパティの1つはウィンドウオブジェクトです。このオブジェクトから、ドキュメントを含む残りの要素を取得できます。 このプロパティに加えて、ウィンドウは他の多くの機能もサポートしています。
- x、y-ウィンドウ座標
- 幅、高さ -ウィンドウサイズ
- title-ウィンドウのタイトル
- menu-ウィンドウの上部に配置されるアプリケーションのメインメニュー
- isTransparent-ウィンドウが透明かどうか
- isFullscreen-ウィンドウが全画面で開いているかどうか
- isKioskMode-アプリケーションがキオスクmodで開いているかどうか
オブジェクトは、プロパティに加えて、多数のメソッドをサポートしています。 主な方法を以下に示し、便宜上グループ化しています。
ウィンドウの位置とサイズを変更する方法:
- moveTo -x座標とy座標としてパラメーターに渡された位置にウィンドウを移動します
- moveBy-ウィンドウを特定のピクセル数だけ右および下に移動します(負の引数を左および上に設定する場合)
- resizeTo-ウィンドウのサイズを変更します。最初の引数は幅を示し、2番目はウィンドウの高さを示します
- resizeBy-ウィンドウを特定のピクセル数だけ右および下にサイズ変更します(負の引数を左および上に設定する場合)
- setPosition-引数として渡されるウィンドウの特定の位置を設定します(現在は 'center'のみがサポートされています)
フォーカスと可視性を操作する方法:
- focus-ウィンドウにフォーカスを移すためのパラメーターなしのメソッド
- blur-ウィンドウを非アクティブにするパラメータなしの方法
- hide-ウィンドウを非表示にします
- show-ウィンドウを表示しますが、引数としてfalseを渡すと、メソッドは非表示として機能します
ウィンドウを閉じる、最小化/拡張を制御する方法:
- close-ウィンドウを閉じます;この場合、closeイベントが発生しますが、引数としてtrueを渡すと、イベントは発生しません
- reload-ウィンドウをリロードする
- reloadDev-ウィンドウをリロードしますが、開発者要素を使用します
- 最大化 -ウィンドウを全画面表示で開きます
- unmaximize-ウィンドウを開いた後、ウィンドウを元のサイズに戻します
- 最小化 -ウィンドウを最小化
- 復元 -ウィンドウを展開し、最小化の反対側
- setShowInTaskbar-タスクバーにウィンドウを表示するかどうか
- setAlwaysOnTop-ウィンドウを他のウィンドウの上に表示するかどうか
状態を管理する方法:
- enterFullscreen、leaveFullscreen、toggleFullscreen-フルスクリーンモードコントロール
- enterKioskMode、leaveKioskMode、toggleKioskMode-キオスクモードを制御します
- setTransparent-渡された引数に応じて、ウィンドウの透明度を設定/クリアします
- showDevTools-開発者ツールを表示
- closeDevTools-開発者ツールを非表示
- isDevToolsOpen-チェック:開発者ツールは開いていますか
ウィンドウのサイズを変更する機能を制御する方法
- setResizable-画面のサイズを変更する機能を設定/リセットします
- setMaximumSize-最大画面サイズの制限を設定します(最初の引数は幅、2番目は高さです)
- setMinimumSize-最小画面サイズに制限を設定します(最初の引数は幅、2番目は高さです)
したがって、 トレイおよびウィンドウオブジェクトに精通しているので、 トレイに最小化する機能を記述します。 これを行うには、ボタンまたはリンクなどの要素をマークアップに追加します(前述のとおり)。
<a ng-click="ctrl.toTray()"> </a>
そして、コントローラーを次のように変更します。
コントローラーコード
(function () { 'use strict'; angular .module('main', []) .controller('MainCtrl', ['$scope', 'CryptoService', MainCtrl]); function MainCtrl($scope, CryptoService) { var self = this; var localStorageKey = "loginPasswordData" this.data = []; var gui = require('nw.gui'); var clipboard = gui.Clipboard.get(); var win = gui.Window.get(); var tray = new gui.Tray({ title: 'Tray', icon: 'img/test.png' }); tray.on("click", restoreFromTray); this.remove = remove; this.copy = copy; this.add = add; this.toTray = toTray; load(); $scope.$watch("ctrl.data", save, true); return this; function remove(ind){ self.data.splice(ind, 1); }; function copy(ind){ clipboard.set(self.data[ind].password); }; function add(){ self.data.push({login: "login", password: "password"}); }; function load(){ var text = localStorage.getItem(localStorageKey); if(text) { self.data = CryptoService.decrypt(text); } } function save(){ if(self.data) { localStorage.setItem(localStorageKey, CryptoService.encrypt(self.data)); } } function toTray(){ win.minimize(); win.setShowInTaskbar(false); } function restoreFromTray(){ win.restore(); win.setShowInTaskbar(true); } } })();
また、この例が機能するには、 imgフォルダーを作成し、そこにトレイアイコン(この例ではimg / test.png )を配置する必要があります。
おわりに
記事の一部として、スタイルから機能の改善まで、さまざまな方法で改善できるプロトタイプアプリケーションを作成しました。 例:
- 最初の10個のパスワードのkeydownイベントにサブスクライブできます。0から9のボタンをクリックすると、パスワードをクリップボードにコピーします。これにより、プログラムの作業が簡素化され、高速化されます。
- パスワードだけでなくログインもコピーする方法を追加します