Created
November 1, 2020 09:02
-
-
Save earlgreyxxx/307ec802d0925067fe23576223dfa03f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************* | |
ミッション: | |
ローカルのエクセルファイルを選択して疑似グリッドビュー編集を行う。 | |
*******************************************************************************/ | |
(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