JavaScriptでファイルのインポート、エクスポートを実装する

Chrome/Firefoxの拡張機能で、設定をインポート、エクスポートする機能が欲しいといった要望があったので、まずはどんな感じにインポート、エクスポートすれば良いんだっけ、、ってことでJavaScriptで簡単なサンプル書いてみました。

コード

下記のようなHTMLを用意します。インポート、エクスポート用のボタンがあって、インポートしたものを表示するエリアを用意しておきます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <button type="button" id="inputFile">Import</button>
    <pre><code id="contents"></code></pre>
    <button type="button" id="outputFile">Export</button>
    <script src="file.js"></script>
  </body>
</html>

JavaScriptは下記のような感じで。

let currentContents = '';
const displayElement = document.getElementById('contents');

document.getElementById('inputFile').addEventListener('click', (e) => {
  const fileInput = document.createElement('input');
  fileInput.type = 'file';
  fileInput.setAttribute('hidden', true);

  fileInput.addEventListener('change', (e) => {
    const file = e.target.files[0];
  
    const reader = new FileReader();
    reader.onload = (e) => {
      const fileContents = e.target.result;
      displayElement.textContent = fileContents;
      currentContents = fileContents;
    }
    reader.readAsText(file);
  }, false);
  
  document.body.appendChild(fileInput);
  fileInput.click();
  fileInput.remove();
}, false);


document.getElementById('outputFile').addEventListener('click', (e) => {
  const downloadLink = document.createElement('a');
  downloadLink.download = 'export.txt';
  downloadLink.href = URL.createObjectURL(new Blob([currentContents], { 'type' : 'text/plain' }));
  downloadLink.setAttribute('hidden', true);

  document.body.appendChild(downloadLink);
  downloadLink.click();
  downloadLink.remove();
}, false);

インポートのボタンが押下された際に、ファイル選択用のinput要素を生成してclickを呼び出してファイル選択ダイアログを表示させます。
ファイルが選択されたら、それをFileReaderを使って読みだして表示します。

エクスポートのボタンが押下されたら、BlobからURLを生成し、それをリンクとしてa要素を生成してclickといった流れでダウンロードさせています。

Firefoxだとbody配下に入れないとclickが効かないので、body.appendChildしてremoveといったことをやっています。

動作

とりあえずFirefox、Chrome、Edgeの最新バージョンで動作することを確認済みです。

f:id:onozaty:20191014010546g:plain

Redmine: View customize plugin の v2.5.0 をリリースしました

View customize plugin の v2.5.0 をリリースしました。

今回のリリースでの変更点は下記の2つとなります。

ViewCustomize.context にユーザの最終ログイン日時を追加

Pull requestをいただき、ViewCustomize.context.user.lastLoginOnで最終ログイン日時を参照できるようにしました。
利用するシチュエーションはあまり無いのかもしれませんが、下記の問題を対応するために使いたいとのことだったので、今回対応することとしました。

ISO 8601形式の文字列として取得できます。

f:id:onozaty:20191006234414p:plain

APIアクセスキーの自動生成をオプションとして提供

APIアクセスキーの自動生成をオプションとして指定できるようにしました。

プラグインの設定画面から設定できます。

f:id:onozaty:20191006234921p:plain

APIアクセスキーは、個人設定画面のAPIアクセスキーの「表示」リンクを初めて押下したタイミングで生成されます。そのため、View cutomizeでユーザのAPIアクセスキーを使う場合には、各ユーザに操作してもらう必要があったのですが、このオプションをONにすると、存在しない場合に自動で生成するようになるため、各ユーザでの操作は不要になります。

redmine-issue-loader のバージョン2.1.0をリリースしました

CSVを読み込んでRedmineのチケットを新規作成、更新するツール、redmine-issue-loaderのバージョン2.1.0をリリースしました。

対象のフィールドを増やして欲しいとの要望があったので、今回下記のフィールドを追加しました。これで全部対応できたはず、、

  • 担当者
  • 対象バージョン
  • 開始日
  • 期日
  • 進捗率
  • 予定工数
  • プライベート

詳しい利用方法は下記の日本語READMEをご参照ください。

ShortcutKey2URL for Chrome のバージョン1.2.0をリリースしました

ShortcutKey2URL for Chrome のバージョン1.2.0をリリースしました。

ShortcutKey2URL は、ショートカットキーを使用してURLを開いたり、移動したり、JavaScriptを実行できる拡張機能です。

スタートアップキーであらかじめ設定しておいた動作の一覧を表示し、次のキーでその動作を実行します。

f:id:onozaty:20171018003430p:plain

今回のバージョンより、Script欄にjavascriptスキームのまま書けるようになりました。Firefox版で先に対応しているものですが、ブックマークレットの内容をそのまま書く方が多いようで、嵌る人が多かった箇所になります。

ShortcutKey2URL(Firefox版)の 4.1.0 をリリースしました

バージョン4.1.0 を先ほどリリースしました。

今回の大きな変更点として、Scriptにjavascriptスキームのまま書けるようにしました。

ブックマークレットを登録する際に、javascriptスキームで書かれたものをそのまま登録してしまい、うまく動かないといった問い合わせがあり、javascriptスキーム部分を削除して、デコードしたものを記入してください、、っていうのは、かなり不便だと思ったので、拡張側で同じことを行うようにして対処しました。これでブックマークレットの内容をそのまま記入してもらえばOKとなりました。

あと雑多な変更として、Chrome版のバージョン1.1.0で既に対応していたものをFirefox版に取り込んでいます。

Redmine: View customize plugin の v2.4.0 をリリースしました

View customize plugin の v2.4.0 をリリースしました。

下記の2つに対応しています。

マルチバイトのWikiページにてエラーが発生する問題対処

IE11+Wikiでマルチバイトのページを表示した場合に、エラーが発生する場合がありました。
ローカルで上記組み合わせで再現できていなかったのですが、報告していただいた方にいろいろ試していただいたところ、URLを取り出した際にUTF-8として不正バイトシーケンスが含まれることがあり、そのせいでエラーとなっていることがわかりました。

不正なバイトを置換するようにして回避しています。

全てのカスタマイズに対して無効/有効を切り替え可能に

全てのカスタマイズを一括で無効/有効に出来るようにしました。
全てを無効にしたいといった場合、今まではいちいち各スクリプトの編集画面までいって切り替える必要がありましたが、これが入ったことによって、ワンクリックで切り替えられるようになりました。

f:id:onozaty:20190907222815g:plain

SUMMER SONIC 2019 (2019年8月18日@幕張メッセ)

SUMMER SONIC 2019の3日目に参戦しました。複数ステージあるフェスは初めてです。

f:id:onozaty:20190818132552j:plain:w300

開場時間の9時くらいに着くように、、って思っていたのですが、なんだかんだで着いたのは9時30分頃になってしまい、物販で元々狙っていたのは全部売り切れでした。後から知ったのですが、物販は8時から開始だったので、9時30分じゃ遅すぎたようです...
それでもグッズが欲しくてグッズ売り場を回ることに。場所によって商品の在庫状況が違っていて、マリンスタジアムが一番品薄で、次にメッセの外、一番残っていたのはメッセの中でした。メッセの中の方は、10時過ぎていても、まだTシャツが何種類か残っていました。ということでTシャツとフードつきのタオル買って準備完了です。

最初はメッセ内を回ってみようということで、メッセ内をぶらぶらしながら腹ごしらえ。お昼前だったからか、フードエリアはまだすいていて、並ぶことなく買えました。
サカノウエユニークの「とりそば」をいただいたのですが、とても美味しかったです。

各ステージがどんな感じかな、、って回って、SHAED、Kizuna AIをちょこっと見て、最初にしっかり観たのは女王蜂のステージからでした。
事前知識無い状態で観たのですが、一気に引き込まれました。アヴちゃんのカリスマ性すごい。途中で声が切り替わるのも、最初は2人で歌っているのか、それともエフェクト?って思っていたのですが、売春のときにしっかり歌っているの見て、こんなキレイに2種類の声だせるのか、、ってびっくりしました。

こういう新しい出会いがあるから、フェスは楽しい。

ここからはマリンスタジアムに移動します。マリンスタジアムとメッセの間は2回ほど往復しましたが、バスが出ているのでらくちんでした。そこまで遠くないとはいえ、炎天下の中あるくとなると、一日体力持たないかなと、、

MARINE STAGEで最初に観るのはPerfumeです。後半のことを考えて、体力温存でスタジアムの席で観ました。

スタジアムの前の方で。昼間はまだ席も全然空いていて、ゆったりと観れました。(サマソニはアーティストの写真撮影NGなので、開演前の写真で)
ただ、アリーナの方が盛り上がっていたので、アリーナで観れば良かったな、、と後からちょっと後悔。。

Pefumeのメジャーな曲はだいたい知っているつもりで望んだのですが、知らない曲が多かったです。直近のツアーのセトリ確認して、ちゃんと勉強してくれば良かった。。
生でパフォーマンス見れたのは感動しました。MCもいい。

続いてはアリーナに移動して、BLACKPINKです。Kill This Love聞いてから好きになって、今回とても楽しみにしていました。
プラチナエリアだったのですが、ステージの端まで来てくれたのもあって、すごく近くで観れました。カワイイし、カッコいい。さらに好きになりました。

ちなみに楽曲は韓国語の方で予習していたのですが、日本語バージョンのほうを歌っていたので、ちょっと違和感がありました。これだけグローバルに売れている状況だと、日本にいても日本語バージョンより韓国語バージョンの方が耳にする機会が多いと思うのですが、どうなんですかね。

続いてBEACH STAGEに歩いて移動します。山崎まさよしを聴くために。
ちょうど「僕はここにいる」を歌い始めるところで、続いて「One more time, One more chance」と、バラード2曲を生で聴けて幸せでした。ほんとうまい。

ここからMARINE STAGEに戻ります。Alan Walkerのライブ終盤で、アリーナはもちろん、スタジアムもかなり埋まっていました。
Alan Walkerこれでまだ20ちょいか、、すごいな、、

初のサマソニだし、いろいろな位置で観て見よう、、ってことで、続くZEDDはスタジアムの一番上で。 スタジアムの良いところは、食事しながら観れるところですよね。
ZEDDは1時間ぶっ続けでヒット曲流しまくりです。全部ヒット曲なのスゴイ。スタジアムの上のほうも満席で、スタジアム全体が盛り上がっていました。

最後のThe Chainsmokersは再度アリーナで。プラチナエリアはアリーナ前方の左右にあったのですが、上から見ていて明らかに右の方が空いていたので右側で。斜めですが、こんな感じで近いところで観れました。
プラチナじゃないセンターの方が、より見やすくて、ぎゅうぎゅうな感じで、ライブの一体感味わえそうですが、頻繁に移動したことを考えると、プラチナでよかったなと思いました。途中から入って前の方いけそうも無かったので。

The ChainsmokersをDJと呼ぶのにはちょっと違和感あって、他のアーティスト迎え入れてヒット曲たくさん出しているけど、ドリューも歌うし、ライブではドラマーも一緒に3人でやっているので、バンドっぽい感じもするという、、今回のライブでもドラムソロがあったりしました。ほんと一員のような感じです。(5SOSとのコラボのWho Do You LoveのPVにも普通に一員として出ていたりする)
ドリューはステージ上を激しく動き回って、歌を歌って、ギターも弾いて、DJ卓でドラム叩いたり、、とても情熱的でした。

フィナーレには花火もあがり、とても感動的なステージでした。

サマソニまた行きたい!(けど来年は東京オリンピックで無いので、再来年かな、、)