HandsOntableとローカルストレージで偽EXCEL

HandsonTableでEXCELチックなものを作ろうとして
去年ごにょごにょしてたけど。まとまった時間がようやく取れたので
ひとまずのことはできるようにした。

特にセルに色を付けた状態を保存する箇所は何とか
実装させたくて色々と調べたものの分からず。強引な方法で
解決してます。
枠線とかメニューの日本語化はコンテキストメニュー周りで
問題が出てるみたいでへっぽこの自分では手に負えないので
断念。まぁそれ以外は何とか動くんでこれにて完成?ってことで

しかしVisualStudioCodeは結構軽くて便利だったりする。
そんな使いこなしていないけど

以下JSのソース、HTMLとCSSはまんま

/*refer
  http://my-waking-dream.blogspot.jp/2013/12/live-search-filter-for-jquery.html
  http://ja.stackoverflow.com/questions/20343/handson-table%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%AE%E9%96%8B%E7%99%BA
  http://qiita.com/do_m_gatoru/items/b0f8d1d18b7037e5cba2
  http://stackoverflow.com/questions/28309993/anyway-to-filter-rows-with-handsontable
  http://jsfiddle.net/awyjnbj6/
  http://stackoverflow.com/questions/40552974/handsontable-header-search-input-text-is-cleared-intermittently-on-scroll
  http://stackoverflow.com/questions/33173850/how-do-i-format-the-column-headers-in-handsontable
  https://teratail.com/questions/36228
  http://qiita.com/PianoScoreJP/items/be721f1b06745c2bbc39
  http://qiita.com/opengl-8080/items/9d25e106ff48b66cb908
  http://docs.handsontable.com/0.18.0/CommentEditor.html
  https://docs.handsontable.com/0.29.2/Comments.html
  http://qiita.com/mas0061/items/5ff36f63f39a6ada80d1
  https://github.com/handsontable/handsontable/issues/3807
*/


//HadsonTable用
var grid, hot, myData, myCells, styles ,resultRow;

//ボタン設定
$(loaded);

function loaded() {
    if (window.localStorage) {
        showContent();
        SetProperty();         //保存している色を設定する
        //ローカルストレージ内データ削除ボタン挙動
        $("#delData").click(
            function() {
                var myRet = confirm("PC内の投稿情報を全削除します。よろしいですか?");
                if (myRet) {
                    clearContent();
                    localStorage.clear();
                }
            });
        //保存ボタン挙動
        $("#saveButton").click(
            function() {
                saveContent();
            });
        //クリアボタン挙動
        $("#clearButton").click(
            function() {
                var myRet = confirm("全てのセルの内容をクリアします。よろしいですか?");
                if (myRet) {
                    clearContent();
                }
            }
        );
    } else {
        alert("未対応のブラウザです。ChromeもしくはFireFoxをご利用ください。");
    }
}

// ローカルストレージに保存した値をテーブルに表示する
function showContent() {
    //データ情報
    var key, value = [];
    key = "gridData";
    value = localStorage.getItem(key);
    if (value === "undefined") {
        myData = [
            ["", "", "", ""]
        ];
    } else {
        myData = JSON.parse(value);
    }
    //セルの色変更
    var TableStyles = function(hot) {
        var self = this;
        var _cellStyles = [];
        var _createStyle = function(row, col, cellcolor, fontcolor) {
            var style = {
                row: row,
                col: col,
                renderer: function(instance, td, row, col, prop, value) {
                    Handsontable.renderers.TextRenderer.apply(this, arguments);
                    td.style.color = fontcolor;
                    td.style.backgroundColor = cellcolor;
                },
            };
            return style;
        };
        //セルのスタイルを返す
        self.getStyles = function() {
            return _cellStyles;
        };
        //セルのスタイル設定
        self.setCellStyle = function(row, col, cellcolor, fontcolor) {  //, updateTable
            _cellStyles.push(_createStyle(row, col, cellcolor, fontcolor));
            hot.updateSettings({
                cell: self.getStyles()
            });
            hot.render();
        };
        //選択範囲のセルに処理を行う。配列値が0開始なのでループ終了条件に+1している。
        self.setCellsStyle = function(startrow, endrow, startcol, endcol, cellcolor, fontcolor) {
            for (var row = startrow; row < endrow + 1; row++) {
                for (var col = startcol; col < endcol + 1; col++) {
                    self.setCellStyle(row, col, cellcolor, fontcolor); //, false
                }
            }
        };
    };

    //HandsonTable設定
    grid = document.getElementById("grid");
    var settings = {
        data: myData,                           //データ表示
        //        width: 500,                   //全体の横枠指定
        height: 500,                            //全体の高さ指定
        autoColumnSize: true,                   //カラム自動調整
        startRows: 10,                          //初期表示行数
        startCols: 5,                           //初期表示列数
        autoRowSize: true,                      //行高さ自動調整
        autoColumnSize: true,                   //列幅自動調整
        rowHeaders: true,                       //行ヘッダー
        colHeaders: true,                       //列ヘッダー
        columnSorting: true,                    //ソート
        sortIndicator: true,                    //ソートの矢印
        minSpareRows: 1,                        //1行だけの空白セル
        fillHandle: true,                       //possible values: true, false, "horizontal", "vertical" フィル有効
        manualColumnMove: true,                 //ドラッグで移動(列)
        manualColumnResize: true,               //ドラッグでサイズ調整(列) 
        manualRowMove: true,                    //ドラッグで移動(行)
        manualRowResize: true,                  //ドラッグでサイズ調整(行)
        comments: true,                         //コメント(右クリックメニュー)
        mergeCells: true,                       //セル結合(右クリックメニュー)
        customBorders: true,                    //罫線(右クリックメニュー)
        renderAllRows: true,
        undo: true,                             //UNDO,REDO
        search: true,                           //検索有効
    };

    hot = new Handsontable(grid, settings);
    styles = new TableStyles(hot);

    //右クリックメニュー
    hot.updateSettings({
        contextMenu: {
            //独自メニュー実装
            callback: function(key, cell, e) {
                var sel = hot.getSelected();
                var startRow = sel[0];          //開始行
                var startCol = sel[1];          //開始列
                var endRow = sel[2];            //終了行
                var endCol = sel[3];            //終了列
                var cellColor = document.getElementById("cellColorPicker").value;
                var fontColor = document.getElementById("fontColorPicker").value;
                // 独自メニューのクリック判定
                switch (key) {
                    case 'setColor':
                        //色設定
                        styles.setCellsStyle(startRow, endRow, startCol, endCol, cellColor, fontColor);
                        break;
                }
            },
            //メニュー
            items: {
                row_above: {
                    name: '上に行を挿入'
                },
                row_below: {
                    name: '下に行を挿入'
                },
                col_left: {
                    name: '左に列を挿入'
                },
                col_right: {
                    name: '右に列を挿入'
                },
                remove_row: {
                    name: '選択行を削除',
                    disabled: function() {
                        return $("#grid").handsontable('countRows') <= 2;
                    }
                },
                remove_col: {
                    name: '選択列を削除',
                    disabled: function() {
                        return $("#grid").handsontable('countCols') <= 1;
                    }
                },
                'setColor': {
                    name: "色を変更"
                },
                undo: {
                    name: '元に戻す'
                },
                redo: {
                    name: 'やり直す'
                },
                make_read_only: {
                    name: 'セルを読取専用にする'
                },
                mergeCells: {
                    name: function() {
                        var sel = this.getSelected();
                        var info = this.mergeCells.mergedCellInfoCollection.getInfo(sel[0], sel[1]);
                        if (info) {
                            return '結合を解除';
                        } else {
                            return 'セルを結合';
                        }
                    }
                },
                alignment: {
                    name: '文字位置指定'
/* どうやらデフォルトのコンテキストメニューのサブメニューを日本語化しようとすると正常に動かない模様
                    submenu: {
                        items: [
                          {key: 'alignment:left', name: '左寄'},
                          {key: 'alignment:center', name: '中央'},
                          {key: 'alignment:right', name: '右寄'},
                          {key: 'alignment:top', name: '上詰め'},
                          {key: 'alignment:middle', name: '中央揃え'},
                          {key: 'alignment:right', name: '下詰め'}
                        ]
                      }
*/
                    },
                borders: {
                    name: '枠線'
/*
                    submenu: {
                        items: [
                          {key: 'borders:top', name: '上罫線'},
                          {key: 'borders:right', name: '右罫線'},
                          {key: 'borders:bottom', name: '下罫線'},
                          {key: 'borders:left', name: '左罫線'},
                          {key: 'alignment:remove border', name: '罫線を消す'}
                        ]
                      }
*/
},
                commentsAddEdit: {
                    name: 'コメントの挿入'
                },
                commentsRemove: {
                    name: 'コメントの削除'
                }
            }
        },
    });
    //検索結果合致の処理
    var searchField = document.getElementById("searchField");
    var resultCount = document.getElementById("resultCount");
    Handsontable.Dom.addEvent(searchField, 'keyup', function(event) {
        filter(('' + this.value).toLowerCase());
        resultRow = hot.countRows() - 1; //0で開始なので-1が必要
        resultCount.innerText = "検索結果:" + resultRow.toString() + "行";
    });
}

// テーブルの内容をローカルストレージに保存する
function saveContent() {
    var content = hot.getData();
    var key = "gridData";
    var val = JSON.stringify(content);
    //データ情報
    localStorage.setItem(key, val);
    // セル情報
    var rows = hot.countRows(); //行数
    var cols = hot.countCols(); //列数
    var i = 0; //セル取得用
    var cellHeight; //行高
    var cellWidth; //列幅
    var styleColor; //文字色
    var bgColor; //背景色
    //コメント
    var comment;
    var commentsPlugin = hot.getPlugin('comments');
    //ローカルストレージ保存用JSON
    var property = [];
    property ="[";
    //プロパティ情報取得(背景色やセルサイズ等)
    for (var row = 0; row < rows - 1; row++) {
        for (var col = 0; col < cols; col++) {
            cellHeight = hot.getRowHeight(row);                  //高さ
            cellWidth = hot.getColWidth(col);                    //幅
            styleColor = $("td").eq(i).css("color");             //文字色
            bgColor = $("td").eq(i).css("backgroundColor");      //背景色
            value = hot.getDataAtCell(row, col);                 //データ
            comment = commentsPlugin.getCommentAtCell(row, col); //コメント(未実装の模様)
            var data = {
                          "Row":row,
                          "Col":col,
                          "Height":cellHeight,
                          "Width":cellWidth,
                          "fontColor":styleColor,
                          "BgColor":bgColor,
                          "Value":value
                        }
            //カンマの処理
            if (col == 0 && row == 0){
                property = property + JSON.stringify(data);
            }else{
                property = property +"," + JSON.stringify(data);
            }
            i = ++i;
        }
    }
    property =property + "]";
    var skey = "Setting";
    var sval = property;
    localStorage.setItem(skey, sval);
    alert("データを保存しました。");
    hot.render();
}

//テーブルの内容をクリアする
function clearContent() {
    hot.clear();
    var background = 'white';
    //色を初期化する
    $('td').css('background-color', 'transparent');
    $('tr').css('background-color', background);

}

//プロパティ情報設定(背景色やセルサイズ等)
function SetProperty(){
    var key,value = [];
    var rows,cols;
    key = "Setting";
    value = localStorage.getItem(key);
    var property = JSON.parse(value);
    if( !property ){
        return;
    }
    var len = property.length;
    for(var i=0;i -1) {
                array.push(data[row]);
                break;
            }
        }
    }
    hot.loadData(array);
}

コメント

このブログの人気の投稿

証券外務員1種勉強(計算式暗記用メモ)

GASでGoogleDriveのサブフォルダとファイル一覧を出力する

マクロ経済学(IS-LM分析)