tmp
Showing posts with label
JavaScript
.
Show all posts
Showing posts with label
JavaScript
.
Show all posts
Thursday, August 16, 2018
Web Push
GCM だの FCM だの VAPID だのいろいろな実装や情報があってわかりづらいのでまとめ * [GCM/FCMでの実装](https://fiahfy.blogspot.com/2018/08/web-push-gcmfcm.html) * [VAPIDでの実装](https://fiahfy.blogspot.com/2018/08/web-push-vapid.html) * [Firebase Cloud Messaging での実装](https://fiahfy.blogspot.com/2018/08/web-push-firebase-cloud-messaging.html) sample project https://github.com/fiahfy/webpush-sample ## 参考 * https://developers.google.com/web/ilt/pwa/introduction-to-push-notifications * https://developers.google.com/web/fundamentals/codelabs/push-notifications/?hl=ja * http://blog.soushi.me/entry/2017/05/18/124558 * https://firebase.google.com/docs/cloud-messaging/js/client
Web Push (Firebase Cloud Messaging)
Web Push に Firebase Cloud Messaging を利用した場合の実装 ### Set gcm_sender_id Firebase project を作成して `103953800507` (固定値) を指定 ドキュメントではこの固定値を入力するように記載されているが省略しても動作はする(謎) `manifest.json` ``` { : "gcm_sender_id": "103953800507" } ``` ### initialize firebase app Firebase project の設定値を指定 `index.html` ``` ``` `app.js` ``` // Retrieve Firebase Messaging object. const messaging = firebase.messaging() ``` ### register service worker ServiceWorker を `/firebase-messaging-sw.js` とする場合は firebase がよろしくやってくれるので省略可 `app.js` ``` navigator.serviceWorker.register('sw.js') .then((registration) => { messaging.useServiceWorker(registration) }) ``` ### request permission and get token `app.js` ``` messaging.requestPermission() .then(() => { console.log('Notification permission granted.') messaging.getToken() .then((currentToken) => { if (currentToken) { sendTokenToServer(currentToken) } else { // Show permission request. console.log('No Instance ID token available. Request permission to generate one.') // Show permission UI. sendTokenToServer(false) } }) .catch((err) => { console.log('An error occurred while retrieving token. ', err) sendTokenToServer(false) }) }) .catch((err) => { console.log('Unable to get permission to notify.', err) }) ``` ### receive push タブの状態(フォアグラウンド/バックグラウンド)に応じて処理する場所が違うのでそれぞれ実装 #### receive on foreground `app.js` ``` messaging.onMessage((e) => { console.log('Message received. ', e) const title = 'Title' const options = { body: e.data.text } new Notification(title, options) }) ``` #### receive on background `sw.js` ``` // Give the service worker access to Firebase Messaging. // Note that you can only use Firebase Messaging here, other Firebase libraries // are not available in the service worker. importScripts('https://www.gstatic.com/firebasejs/5.3.1/firebase-app.js') importScripts('https://www.gstatic.com/firebasejs/5.3.1/firebase-messaging.js') // Initialize the Firebase app in the service worker by passing in the // messagingSenderId. firebase.initializeApp({ 'messagingSenderId': "
" }) // Retrieve an instance of Firebase Messaging so that it can handle background // messages. const messaging = firebase.messaging() messaging.setBackgroundMessageHandler((e) => { console.log('Message received. ', e) // Customize notification here const title = 'Title' const options = { body: e.data.text } return self.registration.showNotification(title, options) }) ``` ### send push `firebase-admin` を利用、 Firebase の サーバアカウントキーをダウンロードし `key.json` にリネーム `'TOKEN'` に対象の登録トークンを指定 `main.js` ``` const admin = require('firebase-admin') const serviceAccount = require('./key.json') admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }) // See documentation on defining a message payload. const message = { data: { text: 'Here is a payload!' }, token: 'TOKEN' } // Send a message to the device corresponding to the provided // registration token. admin.messaging().send(message) .then((response) => { // Response is a message ID string. console.log('Successfully sent message:', response) }) .catch((error) => { console.log('Error sending message:', error) }) ``` 送信 ``` node main.js ```
Web Push (VAPID)
Web Push に VAPID を利用した場合の実装方法 ### generate VAPID public/private keys `generate_vapid_keys.js` ``` const webPush = require('web-push') const vapidKeys = webPush.generateVAPIDKeys() const keys = { publicKey: vapidKeys.publicKey, privateKey: vapidKeys.privateKey, } console.log(keys) ``` 生成 ``` node generate_vapid_keys.js ``` ### register service worker FCMの場合と変わらず `app.js` ``` navigator.serviceWorker.register('/sw.js') .then((registration) => { swRegistration = registration }) ``` ### subscribe `applicationServerKey` に上記で生成した公開鍵を指定 `app.js` ``` swRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: "PUBLIC_KEY" }) .then((subscription) => { // send subscription to server }) ``` ### receive push FCMの場合と変わらず `sw.js` ``` self.addEventListener('push', (e) => { console.log('[Service Worker] Push Received', e) const title = 'Title' const options = { body: e.data ? e.data.text() : 'Empty payload' } e.waitUntil(self.registration.showNotification(title, options)) }) ``` ### send push 暗号化周りが面倒なので `web-push` を利用 `'PUBLIC_KEY'`, `'PRIVATE_KEY'` にそれぞれ生成した公開鍵/秘密鍵を指定 `'SUBSCRIPTION'` は購読時に取得したものを指定 `main.js` ``` const webPush = require('web-push') const payload = 'Here is a payload!' const options = { vapidDetails: { subject: 'mailto:example_email@example.com', publicKey: 'PUBLIC_KEY', privateKey: 'PRIVATE_KEY' }, TTL: 60 } webPush.sendNotification( 'SUBSCRIPTION', payload, options ) ``` 送信 ``` node main.js ```
Web Push (GCM/FCM)
送信のみにFCMを利用した場合の実装方法 Firefox のみの話でいうと FCM を利用しないためFCM周りの設定は省略できる (Chromeを考えると必須ではあるが) ### Set gcm_sender_id Firebase project を作成して `送信者 ID` を指定 `manifest.json` ``` { : "gcm_sender_id": "SENDER_ID" } ``` ### register service worker `app.js` ``` navigator.serviceWorker.register('/sw.js') .then((registration) => { swRegistration = registration }) ``` ### subscribe `app.js` ``` swRegistration.pushManager.subscribe({ userVisibleOnly: true }) .then((subscription) => { // send subscription to server }) ``` `userVisibleOnly` は現状必須だが Firefox だと省略できる ### receive push `sw.js` ``` self.addEventListener('push', (e) => { console.log('[Service Worker] Push Received', e) const title = 'Title' const options = { body: e.data ? e.data.text() : 'Empty payload' } e.waitUntil(self.registration.showNotification(title, options)) }) ``` ### send push #### without data payloads ペイロードなしの通知は endpoint と サーバーキーの指定のみで送信できる サーバーキー は Firebase project に記載されているものを使用 ``` curl "END_POINT" --request POST --header "TTL: 60" --header "Content-Length: 0" --header "Authorization: key=SERVER_KEY" ``` #### with data payloads ペイロードありの通知は暗号化周りが面倒なので `web-push` を利用 `'SUBSCRIPTION'` は購読時に取得したものを指定 `main.js` ``` const webPush = require('web-push') const payload = 'Here is a payload!' const options = { gcmAPIKey: 'SERVER_KEY', TTL: 60 }; webPush.sendNotification( 'SUBSCRIPTION', payload, options ) ``` 送信 ``` node main.js ```
Thursday, July 14, 2016
arguments in arrow function
アロー関数内だと `arguments` で引数が取得できないので以下で対応する ```javascript function foo() { console.log(arguments) // {"0":"a","1":"b","2":"c"} } const bar = (...args) => { console.log(arguments) // {"0":{}} console.log(args) // ["a","b","c"] } foo('a', 'b', 'c') bar('a', 'b', 'c') ``` * https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/arrow_functions#Lexical_arguments
Friday, August 1, 2014
javascript class
javascriptでの変数、メソッドの定義の仕方について 継承を考えると面倒なので今回は無視 ##一般的な方法 ```javascript var MyClass = function(){ var privateProp = 1; this.publicProp = 2; var me = this; var privateMethod = function(){ console.group('private method called'); console.log('private = ' + privateProp); console.log('public = ' + me.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); }; this.privilegedMethod = function(){ console.group('privileged method called'); console.log('private = ' + privateProp); console.log('public = ' + this.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); }; privateMethod(); }; MyClass.staticProp = 11; MyClass.staticMethod = function(){ console.group('static method called'); console.log('private = ' + this.privateProp); console.log('public = ' + this.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); }; MyClass.prototype.publicMethod = function(){ console.group('public method called'); console.log('private = ' + this.privateProp); // undefined console.log('public = ' + this.publicProp); // undefined console.log('static = ' + MyClass.staticProp); console.groupEnd(); }; var c = new MyClass(); console.group('property access test'); console.log('private = ' + c.privateProp); // undefined console.log('public = ' + c.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); console.group('method access test'); //c.privateMethod(); // Uncaught TypeError: undefined is not a function c.privilegedMethod(); c.publicMethod(); MyClass.staticMethod(); console.groupEnd(); ``` 比較的クラスっぽい挙動になる * `const(or final)` が表現できない * `static` の private or public の表現ができない * プライベートプロパティのアクセスにpublidではなくprivileged?とかいう変なメソッドをcallしないといけない * 上記の理由でpublicメソッドを使いづらい * じゃあpublicをprivilegedで置き換えればいいじゃん * でも `var MyClass = function(){...}` の部分はインスタンス生成の度に複製されるので、メモリ的にいまいち ##Google JavaScript Style Google JavaScript Style で書き直してみる ```javascript /** * @constructor */ var MyClass = function() { this.privateMethod_(); }; /** @public */ MyClass.staticProp = 11; /** @public */ MyClass.staticMethod = function() { console.group('static method called'); //console.log('private = ' + this.privateProp_); //console.log('public = ' + this.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); }; /** @private */ MyClass.prototype.privateProp_ = 1; /** @public */ MyClass.prototype.publicProp = 2; /** @private */ MyClass.prototype.privateMethod_ = function() { console.group('private method called'); console.log('private = ' + this.privateProp_); console.log('public = ' + this.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); }; /** @public */ MyClass.prototype.publicMethod = function() { console.group('public method called'); console.log('private = ' + this.privateProp_); console.log('public = ' + this.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); }; var c = new MyClass(); console.group('property access test'); //console.log('private = ' + c.privateProp_); console.log('public = ' + c.publicProp); console.log('static = ' + MyClass.staticProp); console.groupEnd(); console.group('method access test'); //c.privateMethod_(); c.publicMethod(); MyClass.staticMethod(); console.groupEnd(); ``` 一般的な方法よりはきれいにみえる * 基本的にアノテーションでスコープを表現する * const は @const で表現する * private, public は @private, @public で表現する * @private なものには 最後に `_` をつける * @private な変数、メソッドにも普通にアクセスできてしまう(書き方自体はpublicと変わらない為 あくまでもルールなので、無視しようとすればできてしまうが、 Closure Linterでチェックをするとアノテーションに基づいてちゃんと警告を出してくれる
Thursday, March 13, 2014
選択範囲の取得
JavaScriptで選択範囲の取得をするのには `window.getSelection` か `document.selection` を使用して ```javascript function getSelectionText(){ if (window.getSelection) { return window.getSelection().toString(); } else if (document.selection) { return document.selection.createRange().text; } return null; } ``` とすれば良いが IE10,11とFF?では対象のelementがinput=text, textareaの場合にwindow.getSelectionで取得できないので考慮する (IE10ならdocument.selectionがまだ使えるのでそれで取得してもいいけど微妙) ```javascript function getSelectionText(){ if (window.getSelection && document.activeElement){ var userSelection; if (document.activeElement.nodeName == "TEXTAREA" || (document.activeElement.nodeName == "INPUT" && document.activeElement.getAttribute("type").toLowerCase() == "text")){ var ta = document.activeElement; userSelection = ta.value.substring(ta.selectionStart, ta.selectionEnd); } else { userSelection = window.getSelection(); } return userSelection.toString(); } else if (window.getSelection) { return window.getSelection().toString(); } else if (document.selection) { return document.selection.createRange().text; } return null; } ``` ###参考 * http://forums.mozillazine.org/viewtopic.php?f=25&t=2268557
Older Posts
Home
Subscribe to:
Posts (Atom)