Markdown Note Apri を2年ぶりにバージョンアップしました。

markdown.aprifield.com

オンラインで利用可能な Markdown エディターを公開しています。 エディター部には VSCode でも利用されている Monaco Editor を採用しています。

Markdown Note Apri を2年ぶりにバージョンアップしましたので、この件について記載します。

はじめに

長らくバージョンアップを行っていませんでしたが、それは利用していないからではなく、ほぼ毎日のように利用しているにもかかわらずほとんど不満がないためバージョンアップが不要だったからでした。

しかし、最近オフラインで利用する機会があり、以前は正常に動作していたはずのオフライン機能が動かない問題が発覚しました。 調査の結果、ブラウザのバージョンアップによるものと判明し、修正が必要でした。

特にスマートフォンにインストールしたメモアプリがオフラインで動作しないのは致命的ですので、この問題を解決することにしました。

仕様変更について

ほとんど不満がないと記載しましたが、いくつか不満がありましたので仕様変更しました。

  • 認証の種類を追加

    今まではGoogle認証でしかログインできず、今のところは問題ないですが特定の環境で使えなくなるリスクを感じていました。 今回、パスワード不要でメールアドレスだけで認証できる機能を追加しました。

  • ノートの保存先の変更

    今まではログインユーザーのGoogleドライブと同期してノートを保存していました。 前述の通り、Google以外でログインできるように変更したため、Googleドライブと同期できるとは限らないようになりました。 結果として、本システムのサービス上にノードを保存するように仕様変更しました。

フレームワークの変更

今回の修正のついでに各種フレームワークのバージョンアップを行いました。

今までは Vue 2 + Vue CLI で開発していましたが Vue 3 + Vite へ移行しました。 いくつかはまるポイントはありましたが、開発効率の改善やビルド速度の改善など基本的には満足していて前のほうが良かったと思えるポイントはないかなと思いました。

今回のバージョンアップのきっかけとなったオフライン対応については、今までは独自にmanifest.jsonを用意したり register-service-workerを利用していましたが、 今回はvite-plugin-pwaを導入しました。 こちらはマニフェストファイルも自動で用意してくれるので実装上はずいぶんすっきりしました。 逆にブラックボックス感がありましたので初学者は一度は自分でマニフェストファイルを用意してみるのがお勧めかなと思いました。

Twitter でフォローしているユーザーとフォローされているユーザーの差分を表示するサービスをつくりました。

following-followers.aprifield.com

トップページにも記載していますが、サービスの詳細は以下の通りです。

  • Twitter でフォローしているユーザーとフォローされているユーザーの差分を表示するサービスです。
  • 表示する情報は Twitter API を利用して取得します。
  • Twitter API の呼び出し制限によるエラーが発生した場合はリトライしますので画面を開いたままお待ちください。
  • 表示可能なユーザー数の上限は 5,000 です。

利用している Twitter API について

利用している API は以下の 3 つです。 フォローしているユーザーとフォローされているユーザーを検索するにはユーザー ID が必要なので 1 つ目の API でユーザー名をもとにユーザー ID を取得しています。 残りの 2 つは各ユーザー検索用の API です。

  • GET /2/users/by/username/:username
  • GET /2/users/:id/following
  • GET /2/users/:id/followers

API 対応する Twitter のオフィシャルドキュメントは以下の通りです。

これらの API はサービス利用者が Twitter で認証しなくても利用可能です。 その代わりに認証トークンが必要でこの値はサーバーで保持して利用しています。

Twitter API の呼び出し制限について

下記サイトの通り、Twitter API にはレートリミットがあります。 https://developer.twitter.com/en/docs/twitter-api/rate-limits

今回利用している API の場合は以下のレートリミットが定義されています。

  • GET /2/users/by/username/:username

App rate limit (Application-only): 900 requests per 15-minute window shared among all users of your app

User rate limit (User context): 900 requests per 15-minute window per each authenticated user

  • GET /2/users/:id/following
  • GET /2/users/:id/followers

App rate limit (Application-only): 15 requests per 15-minute window shared among all users of your app

User rate limit (User context): 15 requests per 15-minute window per each authenticated user

以下の記載内容は推測も含みます。

作成したサービスは Application-only に該当します。 サービスを利用するユーザーごとではなくアプリごとに 15 分間に 15 回しかリクエストできないことになります。 ユーザー一覧を 15 分間に 15 回しか検索できないとなると非常に厳しい制限とになりますが、リクエストする URL の username も含めた制限であるため、同じユーザーに対して何度も検索しなければ制限されません。

表示可能なユーザー数の上限について

表示可能なユーザー数の上限は 5,000 としています。 理由は、すべてのアカウントは最大 5,000 アカウントまでフォローできるためと、前述のレートリミットを考慮した結果です。 ユーザー一覧の API で取得可能なユーザー数は最大で 1,000 であるため、本サービスでは 5,000 に到達するまで繰り返し検索しています。

定期的にクリップボードをクリアするツールをVectorに公開してもらいました。

作ったツールは以下になります。

www.vector.co.jp

ホームページは以下になります。

regular-clipboard-cleaner.aprifield.com

在宅勤務が増えた昨今、個人 PC で働くことも増えたと思いますが、 うっかり個人的な情報を会社の人たちに共有してしまうミスを防ぐ目的で作りました。

Electron で作成しましたので、WindowsmacOS のどちらでも動作します。

署名をしてない状態で公開してもらえるか不安でしたが、アプリを公開するサイトのマニュアルには署名の必要性についての言及はなく、署名なしで問題なく公開していただけました。

マニュアルにはインストール、アンインストールの方法を書いてアーカイブにまとめるように指示されていましたので、以下のようなファイルを用意しました。 ほかのアプリのほとんどは .txt ファイルでしたが、今回のアプリに同梱したファイルは README.md です。

README.md

# Regular Clipboard Cleaner

クリップボード履歴の管理とクリップボードを定期的にクリアするアプリです。

- ホームページ : https://regular-clipboard-cleaner.aprifield.com/
- GitHub : https://github.com/aprifield/regular-clipboard-cleaner
- 連絡先 : aprifield@gmail.com

## Regular Clipboard Cleaner について

このアプリを使うことでクリップボードを定期的にクリアし、クリップボードからの情報漏洩を軽減します。
また、クリップボードの履歴を維持し、クリアした内容を復元することが可能です。

## 特徴

- 定期クリア

クリア間隔は変更することが可能で、1 秒から 1 日を超えるような大きい値を設定することが可能です。
小さい値を指定することで実質的にクリップボードの機能を無効化することが可能で、大きい値を指定することでクリップボード履歴管理アプリのみとして利用することが可能です。

- クリップボード履歴

アプリ起動後はクリップボードを監視して履歴を保存します。
履歴を選択するとクリップボードにコピーして再利用することが可能です。
履歴を保存する件数を設定することが可能で、0 を設定することでこの機能を無効化することが可能です。

- 履歴のテキストを編集

履歴を選択してクリップボードにコピーするときのテキストを編集することが可能です。
編集するためのプログラミング言語は JavaScript です。
特定のキーを押しながら履歴を選択した場合、特定のキーワードを含んでいる場合など、あらゆる条件に応じて独自に編集処理を構築することが可能です。

## 詳細

ホームページをご参照ください。

https://regular-clipboard-cleaner.aprifield.com/

## 動作環境

- Windows の場合

Windows 7 以降

- macOS の場合

macOS 10.11 (El Capitan) 以降

## インストール

- Windows の場合

アーカイブに同梱されている `Regular Clipboard Cleaner Setup.exe` を実行してください。

- macOS の場合

アーカイブに同梱されている `Regular Clipboard Cleaner.dmg` を実行してください。
インストール画面が表示されるので、`Regular Clipboard Cleaner` をドラッグして Applications へドロップしてください。

## アンインストール

- Windows の場合

Windows 標準のアンインストール機能を実行してください。
その後、以下のフォルダーを削除してください。

`C:\Users\{ユーザー名\AppData\Roaming\Regular Clipboard Cleaner`
(`%APPDATA%\Regular Clipboard Cleaner`)

- macOS の場合

Finder で `Regular Clipboard Cleaner` を選択し、ゴミ箱へ入れてください。
その後、以下のフォルダーを削除してください。

`/Users/{ユーザー名}/Library/Application Support/Regular Clipboard Cleaner`
(`~/Library/Application Support/Regular Clipboard Cleaner`)

## 更新履歴

https://github.com/aprifield/regular-clipboard-cleaner/releases

## 免責事項

本アプリの使用による損害等について作者は一切の責任を負いません。

定期的にクリップボードをクリアするツールを作りました。

f:id:aprifield:20210515121947p:plain

作ったツールは以下になります。

regular-clipboard-cleaner.aprifield.com

在宅勤務が増えた昨今、個人 PC で働くことも増えたと思いますが、 うっかり個人的な情報を会社の人たちに共有してしまうミスを防ぐ目的で作りました。 (ネットで検索して見つけたツールが動かなかったので自作しました。)

Electron で作成しましたので、WindowsmacOS のどちらでも動作します。 ソースコードも公開していますので、必要であれば使いやすいようにメンテナンスしてください。

Markdown Note Apri にモバイルの共有機能でノートを作る機能を追加しました。

markdown.aprifield.com

オンラインで利用可能な Markdown エディターを公開しています。 エディター部には VSCode でも利用されている Monaco Editor を採用しています。(モバイル利用時は HTML 標準の textarea に切り替えています。)

f:id:aprifield:20210306092125p:plain

Markdown Note Apri にモバイルの共有機能でノートを作る機能を追加しましたので、この件について記載します。

はじめに

モバイルの共有機能は以下のようなイメージです。

f:id:aprifield:20210301193019j:plain f:id:aprifield:20210301193032j:plain

モバイルで何か操作をしているときにメモを取りたくなることがありますが、その際に共有機能を使うとメールや Line や Twitter を起動して簡単に共有できます。 同じようにメモ帳アプリをインストールしていれば共有により簡単にメモが作成でき、この機能の本サービスに実装しました。

本サービスは PWA として作成していますが、PWA でモバイルの共有機能と簡単に連携できましたので、この件について記載します。

検証環境は Android のみです。

iPhone については未検証です。(なんとなく動かないような気がしています。。。)

実装

実装はとても簡単で manifest.json の変更と、共有結果の取得処理を対応するだけでよいです。 manifest.json を変更するだけでモバイルに共有先として表示されます。

// manifest.json
{
  // この部分を追加
  "share_target": {
    "action": "./index.html", // 共有でリクエストされるURL
    "params": { // 共有で受け取るパラメータ(ここで指定した値がパラメータのキーになる)
      "title": "title",
      "text": "text",
      "url": "url"
    }
  },
}
// 取得処理
const searchParams = new URL(window.location.href).searchParams;
let title = searchParams.get('title') || '';
let text = searchParams.get('text') || '';
let url = searchParams.get('url') || '';

共有方法によっては受け取る値が異なることを考慮する必要があります。

ブラウザで表示中のページを共有すると title に表示しているページのタイトル、text にページの URL が設定されました。 テキストを選択して共有すると title が空で text のみが渡されました。 いろいろ試しましたが url に値が渡されたことはありませんでした。

最終的には以下のような補完処理を入れています。

title = title || text; // title は必ずほしいので title がないなら text を title として利用する
text = text + '\n' + url; // url は受け取れたことはないが念のために取得しておく

まとめ

今回の対応で PWA をさらにネイティブアプリに近づけることができることが分かりました。

Monaco Editorで日本語の入力中に文字がずれる問題と解決方法

オンラインで利用可能な Markdown エディターを公開しています。 エディター部には VSCode でも利用されている Monaco Editor を採用しています。

f:id:aprifield:20200506124517p:plain

今回は、Monaco Editor で日本語入力中に文字がずれる問題とその解決方法について記載します。

ずれが発生すると、以下のような状態となるため非常にストレスです。

f:id:aprifield:20200806092344p:plain

入力を確定するとずれが解消されるため使えなくはありませんが、何とかしたいと思い調査しました。

f:id:aprifield:20200806092424p:plain

いくつかの記事を確認すると、VSCode でも同じ現象が発生するようで、等幅フォントにすると解消するとのことです。 自分の場合は VSCode では発生せず Monaco Editor でのみ発生しましたが、試しに Font-family を変更するとずれが解消しました。

VSCode も Monaco Editor もデフォルトの Font-family は以下の通りです。

Consolas, "Courier New", monospace

等幅フォントにすると解消するとのことで、日本語ではおなじみの "MS ゴシック" を入れて以下のように変更しましたが解消しませんでした。

"MS ゴシック", Consolas, "Courier New", monospace

試しに "MS ゴシック" だけにするとずれが解消したので、ほかのフォントの指定が影響しているらしい、ということがわかりました。 一つずつ削除して検証してみると monospace を削除するとずれが解消することがわかりました。

というわけで、以下のような設定であればすべてずれは解消しました。

"MS ゴシック"
"MS ゴシック", Consolas, "Courier New"
Consolas, "Courier New"
"Courier New"

Font-family は先に指定したフォントが優先されるのに、一番最後に指定されている monospace の有無で動きが変わるのはなぜでしょうか。

とりあえずは解消しましたので、同じ問題に出くわしている方の参考になれば幸いです。

Markdown Note Apri にスペルチェック機能を追加しました。(ただしα版です。)

markdown.aprifield.com

オンラインで利用可能な Markdown エディターを公開しています。 エディター部には VSCode でも利用されている Monaco Editor を採用しています。

f:id:aprifield:20200506124517p:plain

Markdown Note Apri にスペルチェック機能を追加しましたので、この件について記載します。

なお、今回の実装方法ではパフォーマンスが悪いし、機能的にもまだ改善の余地がありそうなため、 α 版機能という扱いで設定画面には (alpha) と書いています。

はじめに

ブラウザの input タグや textarea タグであれば、ブラウザ標準機能でスペルチェックできますが、Monaco Editor の入力項目は input タグや textarea タグではないため、標準機能が利用できません。 Monaco Editor にはスペルチェック機能が搭載されていないため、独自に作りこむ必要があります。

ブラウザですぐに使えるライブラリがあればよかったのですが、そのようなライブラリは見つからず、Web API を呼び出すことで対応しました。 以下の 2 つを検証し、結論としては後者を選択しました。

Azure の Bing Spell Check について

Bing Spell Check は Azure 上で公開されている Web API サービスです。 APIスペルチェック のキーワードで最初にヒットしたのがこれです。 価格 は、個人で使う分には許容範囲でしょうか。

大手のなので期待をもって使ってみましたが、チェックできるテキストの上限が厳しいという問題があり、利用を見送りました。

チェックモードには、校正(proof)とスペル(spell)があり、ドキュメントには以下のように書いてあります。

  • Proof
    • Meant to provide Office Word like spelling corrections. It can correct long queries, provide casing corrections and suppresses aggressive corrections.
    • (スペル修正のような Office Word を提供することを意味します。長いクエリを修正し、大文字と小文字を修正し、積極的な修正を抑制できます。)
  • Spell
    • Meant to provide Search engine like spelling corrections. It will correct small queries(up to length 9 tokens) without any casing changes and will be more optimized (perf and relevance) towards search like queries.
    • (スペル修正のような検索エンジンを提供することを意味します。大文字と小文字を変更せずに小さなクエリ(最大 9 トークン)を修正し、クエリのような検索に対してより最適化されます(パフォーマンスと関連性)。)

Proof であれば上限がないように見えますが、実際に試してみると正常に機能しません。 どんなテキストを指定してもチェックエラーなしの正常終了となります。 使い方が悪いのか?

Spell の場合は正常のチェックしてくれました。 ただし、ドキュメントの通り、長い文章はチェックしてくれません。

将来的に利用するかもしれないので、忘れないように axios でのサンプルコードを載せておきます。

  public async check(): Promise<void> {
    const params = new URLSearchParams();
    params.append('text', 'when+its+your+turn+turn,+john,+come+runing');
    // params.append('mode', 'proof');
    params.append('mode', 'spell');
    params.append('mkt', 'en-us');
    const result = await axios.post(
      'https://api.cognitive.microsoft.com/bing/v7.0/SpellCheck',
      params,
      {
        headers: {
          'Ocp-Apim-Subscription-Key': 'サブスクリプションキー'
        }
      }
    );
  }

textlint について

textlint は、特定のルールにしたがってテキストをチェックするツールです。 英語やそれ以外の言語のスペルチェックのほか、日本語の構文チェックしてくれて、なかなか優秀そうなツールです。

利用可能なルールがまとめられており、ざっと数えると 70 個ほどのルールがあります。

https://github.com/textlint/textlint/wiki/Collection-of-textlint-rule

この中から使えそうなものをピックアップします。 まずは、最大の目的であるスペルチェックに絞って調査しました。

スペルチェックができるルール

スペルチェックができるルールは 5 つほどあります。

textlint-rule-common-misspellings

Wiki に書いてある、よくあるスペルミスをチェックするルールです。

改行コードが CRLF だとエラーを検知してくれないときがあったり、 LF でも検知してくれないケースがありました。 例えば以下のようなパターンで検知してくれませんでした。

{CRLF}
Tihs{CRLF}
{LF}
Tihs is a pen.{LF}

ただ、オフィシャルサイトだとうまく動いているので、使い方が悪かっただけかもしれません。

上記のような問題があったのと、そもそも Wiki にまとめられる程度の単語ではチェックする単語の数が少ないのではないかと思い、利用は見送りました。

textlint-rule-spelling

https://github.com/wooorm/dictionaries に定義されている辞書ベースにチェックするルールです。

英語以外にいろんな言語のチェックをしてくれます。日本語辞書は存在しません。 英語のスペルチェックの場合は dictionary-en を利用するようです。

このルールは数値の 70 などを 0, 7 へ修正するように指示したり、よくわからない指摘をしてくれますが、 他と比べてこれがもっともよかったので、今回はこれを採用しました。

textlint-rule-en-spell

英語に特化したスペルチェックルールです。

textlint-rule-spelling と同様で dictionary-en の辞書を利用するようです。 英語限定でスペルチェックするのであれば、textlint-rule-spelling よりこちらのほうがシンプルでよさそうですが、 Tihs is a pen. っていう単純なスペルミスを検知してくれなかったので textlint-rule-spelling のほうを採用しました。

textlint-rule-ginger

外部サービスである Ginger Proofreading を利用したルールです。

おそらく、スペルチェックとしては優秀でしょうが、このサービスは無料プラン以外に有料プランもあり、将来的な不安があるので未検証です。

textlint-rule-spellchecker

ネイティブ(OS?)の機能を利用してスペルチェックするルールです。

これが使えるならこれが一番いいような印象ですが、Python がないと使えないので未検証です。

スペルチェック以外に使えそうなルール

スペルチェックは textlint-rule-spelling を採用しましたが、textlint にはスペルチェック以外に多くのルールがあります。

検証結果をまとめました。

textlint-rule-prh

表記ゆれをチェックするルールです。

Microsoft Word であれば、1 ファイル内に「フォルダ」と「フォルダー」が混在するような場合に警告を出しますが、 こちらは決まったルールでしかチェックしてくれないようです。

例えば、「プライマリー」という単語は必ず「プライマリ」へ修正するよう指摘します。

少し期待外れだったことと、以下のような指摘もあり、利用を見送りました。

-表記ゆれの修正に特化したルール
+表記ゆれの修まさに特化したルール
-正解ということもない
+正解というこ伴

このルールは定義を指定する必要があり、今回の検証で利用した定義ファイルは https://github.com/prh/rules/blob/master/media/WEB%2BDB_PRESS.yml です。 定義を自分好みに作成すれば利用はありかもしれません。

textlint-rule-web-plus-db

textlint-rule-prh と同じ表記ゆれをチェックするルールです。

textlint-rule-prh とは異なりルールで利用するファイルが固定化されており、こちらは非推奨となっています。 textlint-rule-prh と同様、利用は見送りました。

textlint-rule-ng-word

NG ワードを定義するしてチェックするルールです。

利用したかったのですが、チェックで指摘する行と実際の行が違うので、利用を見送りました。

本ブログを書いている時点で、オフィシャルサイトには以下のように textlint-rule- が 2 回書かれていて、なんとも微妙な状況です。

npm install textlint-rule-textlint-rule-ng-word

textlint-rule-preset-jtf-style

「JTF 日本語標準スタイルガイド」をもとにチェックするルールです。

オフィシャルサイトの通りだと以下をチェックすると思われます。

  1. 本文を、敬体(ですます調)あるいは常体(である調)のどちらかに統一する。
  2. 句読点は「、」と「。」を使う。
  3. 常用漢字表にある漢字を主に使用する。
  4. 動詞の送りがなは本則に従う。
  5. カタカナ語の語尾の長音は省略しない。
  6. 長いカタカナ複合語は中黒または半角スペースで区切る。
  7. 漢字、ひらがな、カタカナは全角で表記する。
  8. 数字とアルファベットは半角で表記する。
  9. 原則として記号類は全角で表記する。
  10. 半角文字と全角文字の間に半角スペースを入れない。
  11. ピリオド(.)、カンマ(,)、スペースは半角で表記する。
  12. 単位の表記を統一する。

この中で個人的に一番使いたいルールは カタカナ語の語尾の長音は省略しない。 ですが、 実際に利用してみるとチェックしてくれなかったので利用を見送りました。

textlint-filter-rule-allowlist

チェックでヒットした単語をエラー扱いにしないためのフィルターです。

スペルチェック機能ではよくある機能だと思いますので利用することにしました。

textlint-filter-rule-comments

特定の範囲の文章のチェックしないようにするためのフィルターです。

<!-- textlint-disable --><!-- textlint-enable --> のコメントを入れることになりますが、 この HTML コメントを無視して描画するか、そのまま描画するかはマークダウンの描画処理次第なので利用を見送りました。

textlint についてのまとめ

textlint には多くのルールがありますが、最終的に利用すると決めたのは以下の 2 つだけです。 ずいぶん時間をかけて調べましたが、こうなってくると、textlint にこだわらないほうが良かったかもしれません。

  1. textlint-rule-spelling
  2. textlint-filter-rule-allowlist

最後に textlint をブラウザから呼び出す必要がありますが、textlint はブラウザで動作させることを想定していないみたいです。 ブラウザで動作させている記事も見つけましたが、今回は Firebase の Cloud Functions にデプロイし API として公開する対応をしました。 それなりに重い処理をしているのでパフォーマンスが悪いです。 性能を上げるにはお金がかかるので、パフォーマンスを上げる予定はありません。

で、出来上がった API は以下になります。 認証しないと使えない内部的な API ですので詳細(パラメータやレスポンス)については割愛します。

https://asia-northeast1-markdown-60249.cloudfunctions.net/lint

まとめ

Markdown Note Apri のスペルチェック機能について記載しました。 ブラウザ上で動作する JavaScript ライブラリって意外にないんですね。