Skip to content

Instantly share code, notes, and snippets.

@earlgreyxxx
Created November 1, 2020 09:02
Show Gist options
  • Save earlgreyxxx/307ec802d0925067fe23576223dfa03f to your computer and use it in GitHub Desktop.
Save earlgreyxxx/307ec802d0925067fe23576223dfa03f to your computer and use it in GitHub Desktop.
/*******************************************************************************
ミッション:
ローカルのエクセルファイルを選択して疑似グリッドビュー編集を行う。
*******************************************************************************/
(function($,undefined) {
// エクセルファイルロードのトリガー
$('input#select-file[type=file]').on('change',on_input_type_file_change);
// グリッドセルのイベントハンドラ登録
$('.row.body')
.on('click','.cell',on_cell_click)
.on('blur','.cell',on_cell_blur)
.on('keydown','.cell',on_cell_keydown);
// ウィンドウサイズ変更のイベントハンドラ登録
$(window).on('resize',on_window_resize).resize();
/************************************************************************
* 以下関数定義
************************************************************************/
// グリッドの高さをウィンドウに合わせて調整
function on_window_resize(e)
{
var h1 = $('.header').outerHeight(true);
var h2 = $(window).height();
var h3 = parseInt($(document.body).css('margin-top')) + parseInt($(document.body).css('margin-bottom'));
var h = h2 - h1 - h3;
//画面下まで高さを伸ばす
$('#excel-grid').height(h);
}
// エクセルファイルの読込完了ハンドラ
function on_excel_file_load(e)
{
// お約束
var data = new Uint8Array(e.target.result);
var workbook = XLSX.read(data, {type: 'array'});
// 一番最初のシートの名前を得る
var n = workbook.SheetNames[0];
// シート名からワークシートオブジェクトをゲト
var ws = workbook.Sheets[n];
// シートの全範囲を取得
// ワークシートオブジェクトの各セルは、エクセルでよく使うA1形式でアクセスできます(ws['A1'], ws['A2']みたいに)
// そして !ref プロパティーには A1:Z10のような形式でセルが使用されている範囲が入っています。
// プログラムで利用するにはメンドクサイのでこの形式を一旦 row/column形式にデコードする必要があります。
// ワークシートオブジェクトについては https://github.com/sheetjs/sheetjs/#sheet-objects を参照。
var range = XLSX.utils.decode_range(ws['!ref']);
// 使用されている最大列数を取得
// デコードされた範囲オブジェクトrange は
// { s: { r: 数字, c: 数字 }, e: { r: 数字, c: 数字 } }
// というような構造になっているようです。
// s は start , e は end , r は row , c は column の略だと思われます。
var rownum = range.e.c + 1;
// グリッド内のセルを初期化
$('.row.head,.row.body').empty();
// 最大列数から CSS のgrid-template-columnsプロパティの値を決めてあげます。
// grid-template-columns: repeat(x,1fr); ここで x は rownumにする
$('.row.head,.row.body').css('grid-template-columns','repeat(' + rownum.toString() + ',1fr)');
// ワークシートをJSONデータに変換
// 第二引数のオブジェクトで headerプロパティを与えていますが、
// これは 各行をオブジェクト(object)ではなく配列(array)に変換するオプションです。
// このオプションの意味は https://github.com/sheetjs/sheetjs#user-content-json を参照。
var json = XLSX.utils.sheet_to_json(ws,{header:1})
// <table>要素を使えばもっと簡単になったけど、敢えてイバラの道を進みます。
var $head = $('#excel-grid > .head');
var $body = $('#excel-grid > .body');
// JSONデータから グリッドのセルを埋めていきます。
$.each(json,function(i,arr) {
var to = i == 0 ? $head : $body;
for(var j=0;j<rownum;j++)
{
var v = arr[j] ? arr[j].toString() : '';
var celldata = {'r':i,'c':j,'v':v};
var attrs = {
'data-cell': JSON.stringify(celldata),
'title': v
};
$('<span>')
.addClass('cell')
.attr(attrs)
.text(v)
.appendTo(to);
}
});
};
// input[type=file]の onchange ハンドラ
function on_input_type_file_change(e)
{
var files = this.files;
var f = files[0];
var reader = new FileReader();
reader.onload = on_excel_file_load;
reader.readAsArrayBuffer(f);
}
// 各セルをクリックした時のイベントハンドラ
function on_cell_click(e)
{
e.preventDefault();
e.stopPropagation();
// セルをクリックしたらセルのclassにeditingを追加
$(this).addClass('editing');
// セルの元の値を undoプロパティに保存
this.undo = this.textContent;
// セルのスタイルを変更
this.setAttribute('style','text-overflow: clip;');
// セルを編集可能にする
this.setAttribute('contentEditable','true');
// フォーカスをあてる
this.focus();
}
// セル編集中にフォーカスが外れたら cell_value_update関数をコールして更新
function on_cell_blur(e)
{
if('true' === this.getAttribute('contentEditable'))
cell_value_update(this);
}
// セルのonkeydownイベントハンドラ
function on_cell_keydown(e)
{
// セル編集中、リターン(エンター)キーとエスケープキーをトラップ
if(e.keyCode == 13 || e.keyCode == 27)
{
e.preventDefault();
// エスケープキーなら復帰
if(e.keyCode == 27)
this.textContent = this.undo;
cell_value_update(this);
}
}
// cell 更新処理
function cell_value_update(cell)
{
// セルの値が保存されていた編集前の値と違っていたら更新
if(cell.textContent !== cell.undo)
{
var o = JSON.parse($(cell).attr('data-cell'));
o.v = $(cell).text();
$(cell).attr('data-cell',JSON.stringify(o));
}
// バックアップを廃棄
delete cell.undo;
// 編集を終了
$(cell)
.removeAttr('contentEditable')
.removeAttr('style')
.removeClass('editing')
.scrollLeft(0);
}
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment