UNPKG

jexcel

Version:

Jspreadsheet is a lightweight, vanilla javascript plugin to create amazing web-based interactive tables and spreadsheets compatible with Excel, Google Spreadsheets and any other spreadsheet software.

1,301 lines (1,175 loc) 562 kB
/** * Jspreadsheet v4.6.0 * * Website: https://bossanova.uk/jspreadsheet/ * Description: Create amazing web based spreadsheets. * * This software is distribute under MIT License */ console.log('Jexcel has been renamed to Jspreadsheet. Please use: npm install jspreadsheet-ce') if (! jSuites && typeof(require) === 'function') { var jSuites = require('jsuites'); require('jsuites/dist/jsuites.css'); } ;(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.jspreadsheet = global.jexcel = factory(); }(this, (function () { 'use strict'; // Jspreadsheet core object var jexcel = (function(el, options) { // Create jexcel object var obj = {}; obj.options = {}; if (! (el instanceof Element || el instanceof HTMLDocument)) { console.error('Jspreadsheet: el is not a valid DOM element'); return false; } else if (el.tagName == 'TABLE') { if (options = jexcel.createFromTable(el, options)) { var div = document.createElement('div'); el.parentNode.insertBefore(div, el); el.remove(); el = div; } else { console.error('Jspreadsheet: el is not a valid DOM element'); return false; } } // Loading default configuration var defaults = { // External data url:null, // Ajax options method: 'GET', requestVariables: null, // Data data:null, // Custom sorting handler sorting:null, // Copy behavior copyCompatibility:false, root:null, // Rows and columns definitions rows:[], columns:[], // Deprected legacy options colHeaders:[], colWidths:[], colAlignments:[], nestedHeaders:null, // Column width that is used by default defaultColWidth:50, defaultColAlign:'center', // Spare rows and columns minSpareRows:0, minSpareCols:0, // Minimal table dimensions minDimensions:[0,0], // Allow Export allowExport:true, // @type {boolean} - Include the header titles on download includeHeadersOnDownload:false, // @type {boolean} - Include the header titles on copy includeHeadersOnCopy:false, // Allow column sorting columnSorting:true, // Allow column dragging columnDrag:false, // Allow column resizing columnResize:true, // Allow row resizing rowResize:false, // Allow row dragging rowDrag:true, // Allow table edition editable:true, // Allow new rows allowInsertRow:true, // Allow new rows allowManualInsertRow:true, // Allow new columns allowInsertColumn:true, // Allow new rows allowManualInsertColumn:true, // Allow row delete allowDeleteRow:true, // Allow deleting of all rows allowDeletingAllRows:false, // Allow column delete allowDeleteColumn:true, // Allow rename column allowRenameColumn:true, // Allow comments allowComments:false, // Global wrap wordWrap:false, // Image options imageOptions: null, // CSV source csv:null, // Filename csvFileName:'jexcel', // Consider first line as header csvHeaders:true, // Delimiters csvDelimiter:',', // First row as header parseTableFirstRowAsHeader:false, parseTableAutoCellType:false, // Disable corner selection selectionCopy:true, // Merged cells mergeCells:{}, // Create toolbar toolbar:null, // Allow search search:false, // Create pagination pagination:false, paginationOptions:null, // Full screen fullscreen:false, // Lazy loading lazyLoading:false, loadingSpin:false, // Table overflow tableOverflow:false, tableHeight:'300px', tableWidth:null, textOverflow:false, // Meta meta: null, // Style style:null, classes:null, // Execute formulas parseFormulas:true, autoIncrement:true, autoCasting:true, // Security secureFormulas:true, stripHTML:true, stripHTMLOnCopy:false, // Filters filters:false, footers:null, // Event handles onundo:null, onredo:null, onload:null, onchange:null, oncomments:null, onbeforechange:null, onafterchanges:null, onbeforeinsertrow: null, oninsertrow:null, onbeforeinsertcolumn: null, oninsertcolumn:null, onbeforedeleterow:null, ondeleterow:null, onbeforedeletecolumn:null, ondeletecolumn:null, onmoverow:null, onmovecolumn:null, onresizerow:null, onresizecolumn:null, onsort:null, onselection:null, oncopy:null, onpaste:null, onbeforepaste:null, onmerge:null, onfocus:null, onblur:null, onchangeheader:null, oncreateeditor:null, oneditionstart:null, oneditionend:null, onchangestyle:null, onchangemeta:null, onchangepage:null, onbeforesave:null, onsave:null, // Global event dispatcher onevent:null, // Persistance persistance:false, // Customize any cell behavior updateTable:null, // Detach the HTML table when calling updateTable detachForUpdates: false, freezeColumns:null, // Texts text:{ noRecordsFound: 'No records found', showingPage: 'Showing page {0} of {1} entries', show: 'Show ', search: 'Search', entries: ' entries', columnName: 'Column name', insertANewColumnBefore: 'Insert a new column before', insertANewColumnAfter: 'Insert a new column after', deleteSelectedColumns: 'Delete selected columns', renameThisColumn: 'Rename this column', orderAscending: 'Order ascending', orderDescending: 'Order descending', insertANewRowBefore: 'Insert a new row before', insertANewRowAfter: 'Insert a new row after', deleteSelectedRows: 'Delete selected rows', editComments: 'Edit comments', addComments: 'Add comments', comments: 'Comments', clearComments: 'Clear comments', copy: 'Copy...', paste: 'Paste...', saveAs: 'Save as...', about: 'About', areYouSureToDeleteTheSelectedRows: 'Are you sure to delete the selected rows?', areYouSureToDeleteTheSelectedColumns: 'Are you sure to delete the selected columns?', thisActionWillDestroyAnyExistingMergedCellsAreYouSure: 'This action will destroy any existing merged cells. Are you sure?', thisActionWillClearYourSearchResultsAreYouSure: 'This action will clear your search results. Are you sure?', thereIsAConflictWithAnotherMergedCell: 'There is a conflict with another merged cell', invalidMergeProperties: 'Invalid merged properties', cellAlreadyMerged: 'Cell already merged', noCellsSelected: 'No cells selected', }, // About message about:"jExcel CE Spreadsheet\nVersion 4.5.0\nWebsite: https://bossanova.uk/jexcel/v3", }; // Loading initial configuration from user for (var property in defaults) { if (options && options.hasOwnProperty(property)) { if (property === 'text') { obj.options[property] = defaults[property]; for (var textKey in options[property]) { if (options[property].hasOwnProperty(textKey)){ obj.options[property][textKey] = options[property][textKey]; } } } else { obj.options[property] = options[property]; } } else { obj.options[property] = defaults[property]; } } // Global elements obj.el = el; obj.corner = null; obj.contextMenu = null; obj.textarea = null; obj.ads = null; obj.content = null; obj.table = null; obj.thead = null; obj.tbody = null; obj.rows = []; obj.results = null; obj.searchInput = null; obj.toolbar = null; obj.pagination = null; obj.pageNumber = null; obj.headerContainer = null; obj.colgroupContainer = null; // Containers obj.headers = []; obj.records = []; obj.history = []; obj.formula = []; obj.colgroup = []; obj.selection = []; obj.highlighted = []; obj.selectedCell = null; obj.selectedContainer = null; obj.style = []; obj.data = null; obj.filter = null; obj.filters = []; // Internal controllers obj.cursor = null; obj.historyIndex = -1; obj.ignoreEvents = false; obj.ignoreHistory = false; obj.edition = null; obj.hashString = null; obj.resizing = null; obj.dragging = null; // Lazy loading if (obj.options.lazyLoading == true && (obj.options.tableOverflow == false && obj.options.fullscreen == false)) { console.error('Jspreadsheet: The lazyloading only works when tableOverflow = yes or fullscreen = yes'); obj.options.lazyLoading = false; } /** * Activate/Disable fullscreen * use programmatically : table.fullscreen(); or table.fullscreen(true); or table.fullscreen(false); * @Param {boolean} activate */ obj.fullscreen = function(activate) { // If activate not defined, get reverse options.fullscreen if (activate == null) { activate = ! obj.options.fullscreen; } // If change if (obj.options.fullscreen != activate) { obj.options.fullscreen = activate; // Test LazyLoading conflict if (activate == true) { el.classList.add('fullscreen'); } else { el.classList.remove('fullscreen'); } } } /** * Trigger events */ obj.dispatch = function(event) { // Dispatch events if (! obj.ignoreEvents) { // Call global event if (typeof(obj.options.onevent) == 'function') { var ret = obj.options.onevent.apply(this, arguments); } // Call specific events if (typeof(obj.options[event]) == 'function') { var ret = obj.options[event].apply(this, Array.prototype.slice.call(arguments, 1)); } } // Persistance if (event == 'onafterchanges' && obj.options.persistance) { var url = obj.options.persistance == true ? obj.options.url : obj.options.persistance; var data = obj.prepareJson(arguments[2]); obj.save(url, data); } return ret; } /** * Prepare the jexcel table * * @Param config */ obj.prepareTable = function() { // Loading initial data from remote sources var results = []; // Number of columns var size = obj.options.columns.length; if (obj.options.data && typeof(obj.options.data[0]) !== 'undefined') { // Data keys var keys = Object.keys(obj.options.data[0]); if (keys.length > size) { size = keys.length; } } // Minimal dimensions if (obj.options.minDimensions[0] > size) { size = obj.options.minDimensions[0]; } // Requests var multiple = []; // Preparations for (var i = 0; i < size; i++) { // Deprected options. You should use only columns if (! obj.options.colHeaders[i]) { obj.options.colHeaders[i] = ''; } if (! obj.options.colWidths[i]) { obj.options.colWidths[i] = obj.options.defaultColWidth; } if (! obj.options.colAlignments[i]) { obj.options.colAlignments[i] = obj.options.defaultColAlign; } // Default column description if (! obj.options.columns[i]) { obj.options.columns[i] = { type:'text' }; } else if (! obj.options.columns[i].type) { obj.options.columns[i].type = 'text'; } if (! obj.options.columns[i].name) { obj.options.columns[i].name = keys && keys[i] ? keys[i] : i; } if (! obj.options.columns[i].source) { obj.options.columns[i].source = []; } if (! obj.options.columns[i].options) { obj.options.columns[i].options = []; } if (! obj.options.columns[i].editor) { obj.options.columns[i].editor = null; } if (! obj.options.columns[i].allowEmpty) { obj.options.columns[i].allowEmpty = false; } if (! obj.options.columns[i].title) { obj.options.columns[i].title = obj.options.colHeaders[i] ? obj.options.colHeaders[i] : ''; } if (! obj.options.columns[i].width) { obj.options.columns[i].width = obj.options.colWidths[i] ? obj.options.colWidths[i] : obj.options.defaultColWidth; } if (! obj.options.columns[i].align) { obj.options.columns[i].align = obj.options.colAlignments[i] ? obj.options.colAlignments[i] : 'center'; } // Pre-load initial source for json autocomplete if (obj.options.columns[i].type == 'autocomplete' || obj.options.columns[i].type == 'dropdown') { // if remote content if (obj.options.columns[i].url) { multiple.push({ url: obj.options.columns[i].url, index: i, method: 'GET', dataType: 'json', success: function(data) { var source = []; for (var i = 0; i < data.length; i++) { obj.options.columns[this.index].source.push(data[i]); } } }); } } else if (obj.options.columns[i].type == 'calendar') { // Default format for date columns if (! obj.options.columns[i].options.format) { obj.options.columns[i].options.format = 'DD/MM/YYYY'; } } } // Create the table when is ready if (! multiple.length) { obj.createTable(); } else { jSuites.ajax(multiple, function() { obj.createTable(); }); } } obj.createTable = function() { // Elements obj.table = document.createElement('table'); obj.thead = document.createElement('thead'); obj.tbody = document.createElement('tbody'); // Create headers controllers obj.headers = []; obj.colgroup = []; // Create table container obj.content = document.createElement('div'); obj.content.classList.add('jexcel_content'); obj.content.onscroll = function(e) { obj.scrollControls(e); } obj.content.onwheel = function(e) { obj.wheelControls(e); } // Create toolbar object obj.toolbar = document.createElement('div'); obj.toolbar.classList.add('jexcel_toolbar'); // Search var searchContainer = document.createElement('div'); var searchText = document.createTextNode((obj.options.text.search) + ': '); obj.searchInput = document.createElement('input'); obj.searchInput.classList.add('jexcel_search'); searchContainer.appendChild(searchText); searchContainer.appendChild(obj.searchInput); obj.searchInput.onfocus = function() { obj.resetSelection(); } // Pagination select option var paginationUpdateContainer = document.createElement('div'); if (obj.options.pagination > 0 && obj.options.paginationOptions && obj.options.paginationOptions.length > 0) { obj.paginationDropdown = document.createElement('select'); obj.paginationDropdown.classList.add('jexcel_pagination_dropdown'); obj.paginationDropdown.onchange = function() { obj.options.pagination = parseInt(this.value); obj.page(0); } for (var i = 0; i < obj.options.paginationOptions.length; i++) { var temp = document.createElement('option'); temp.value = obj.options.paginationOptions[i]; temp.innerHTML = obj.options.paginationOptions[i]; obj.paginationDropdown.appendChild(temp); } // Set initial pagination value obj.paginationDropdown.value = obj.options.pagination; paginationUpdateContainer.appendChild(document.createTextNode(obj.options.text.show)); paginationUpdateContainer.appendChild(obj.paginationDropdown); paginationUpdateContainer.appendChild(document.createTextNode(obj.options.text.entries)); } // Filter and pagination container var filter = document.createElement('div'); filter.classList.add('jexcel_filter'); filter.appendChild(paginationUpdateContainer); filter.appendChild(searchContainer); // Colsgroup obj.colgroupContainer = document.createElement('colgroup'); var tempCol = document.createElement('col'); tempCol.setAttribute('width', '50'); obj.colgroupContainer.appendChild(tempCol); // Nested if (obj.options.nestedHeaders && obj.options.nestedHeaders.length > 0) { // Flexible way to handle nestedheaders if (obj.options.nestedHeaders[0] && obj.options.nestedHeaders[0][0]) { for (var j = 0; j < obj.options.nestedHeaders.length; j++) { obj.thead.appendChild(obj.createNestedHeader(obj.options.nestedHeaders[j])); } } else { obj.thead.appendChild(obj.createNestedHeader(obj.options.nestedHeaders)); } } // Row obj.headerContainer = document.createElement('tr'); var tempCol = document.createElement('td'); tempCol.classList.add('jexcel_selectall'); obj.headerContainer.appendChild(tempCol); for (var i = 0; i < obj.options.columns.length; i++) { // Create header obj.createCellHeader(i); // Append cell to the container obj.headerContainer.appendChild(obj.headers[i]); obj.colgroupContainer.appendChild(obj.colgroup[i]); } obj.thead.appendChild(obj.headerContainer); // Filters if (obj.options.filters == true) { obj.filter = document.createElement('tr'); var td = document.createElement('td'); obj.filter.appendChild(td); for (var i = 0; i < obj.options.columns.length; i++) { var td = document.createElement('td'); td.innerHTML = '&nbsp;'; td.setAttribute('data-x', i); td.className = 'jexcel_column_filter'; if (obj.options.columns[i].type == 'hidden') { td.style.display = 'none'; } obj.filter.appendChild(td); } obj.thead.appendChild(obj.filter); } // Content table obj.table = document.createElement('table'); obj.table.classList.add('jexcel'); obj.table.setAttribute('cellpadding', '0'); obj.table.setAttribute('cellspacing', '0'); obj.table.setAttribute('unselectable', 'yes'); //obj.table.setAttribute('onselectstart', 'return false'); obj.table.appendChild(obj.colgroupContainer); obj.table.appendChild(obj.thead); obj.table.appendChild(obj.tbody); if (! obj.options.textOverflow) { obj.table.classList.add('jexcel_overflow'); } // Spreadsheet corner obj.corner = document.createElement('div'); obj.corner.className = 'jexcel_corner'; obj.corner.setAttribute('unselectable', 'on'); obj.corner.setAttribute('onselectstart', 'return false'); if (obj.options.selectionCopy == false) { obj.corner.style.display = 'none'; } // Textarea helper obj.textarea = document.createElement('textarea'); obj.textarea.className = 'jexcel_textarea'; obj.textarea.id = 'jexcel_textarea'; obj.textarea.tabIndex = '-1'; // Contextmenu container obj.contextMenu = document.createElement('div'); obj.contextMenu.className = 'jexcel_contextmenu'; // Create element jSuites.contextmenu(obj.contextMenu, { onclick:function() { obj.contextMenu.contextmenu.close(false); } }); // Powered by jExcel var ads = document.createElement('a'); ads.setAttribute('href', 'https://bossanova.uk/jexcel/'); obj.ads = document.createElement('div'); obj.ads.className = 'jexcel_about'; try { if (typeof(sessionStorage) !== "undefined" && ! sessionStorage.getItem('jexcel')) { sessionStorage.setItem('jexcel', true); var img = document.createElement('img'); img.src = '//bossanova.uk/jexcel/logo.png'; ads.appendChild(img); } } catch (exception) { } var span = document.createElement('span'); span.innerHTML = 'Jexcel spreadsheet'; ads.appendChild(span); obj.ads.appendChild(ads); // Create table container TODO: frozen columns var container = document.createElement('div'); container.classList.add('jexcel_table'); // Pagination obj.pagination = document.createElement('div'); obj.pagination.classList.add('jexcel_pagination'); var paginationInfo = document.createElement('div'); var paginationPages = document.createElement('div'); obj.pagination.appendChild(paginationInfo); obj.pagination.appendChild(paginationPages); // Hide pagination if not in use if (! obj.options.pagination) { obj.pagination.style.display = 'none'; } // Append containers to the table if (obj.options.search == true) { el.appendChild(filter); } // Elements obj.content.appendChild(obj.table); obj.content.appendChild(obj.corner); obj.content.appendChild(obj.textarea); el.appendChild(obj.toolbar); el.appendChild(obj.content); el.appendChild(obj.pagination); el.appendChild(obj.contextMenu); el.appendChild(obj.ads); el.classList.add('jexcel_container'); // Create toolbar if (obj.options.toolbar && obj.options.toolbar.length) { obj.createToolbar(); } // Fullscreen if (obj.options.fullscreen == true) { el.classList.add('fullscreen'); } else { // Overflow if (obj.options.tableOverflow == true) { if (obj.options.tableHeight) { obj.content.style['overflow-y'] = 'auto'; obj.content.style['box-shadow'] = 'rgb(221 221 221) 2px 2px 5px 0.1px'; obj.content.style.maxHeight = obj.options.tableHeight; } if (obj.options.tableWidth) { obj.content.style['overflow-x'] = 'auto'; obj.content.style.width = obj.options.tableWidth; } } } // With toolbars if (obj.options.tableOverflow != true && obj.options.toolbar) { el.classList.add('with-toolbar'); } // Actions if (obj.options.columnDrag == true) { obj.thead.classList.add('draggable'); } if (obj.options.columnResize == true) { obj.thead.classList.add('resizable'); } if (obj.options.rowDrag == true) { obj.tbody.classList.add('draggable'); } if (obj.options.rowResize == true) { obj.tbody.classList.add('resizable'); } // Load data obj.setData(); // Style if (obj.options.style) { obj.setStyle(obj.options.style, null, null, 1, 1); } // Classes if (obj.options.classes) { var k = Object.keys(obj.options.classes); for (var i = 0; i < k.length; i++) { var cell = jexcel.getIdFromColumnName(k[i], true); obj.records[cell[1]][cell[0]].classList.add(obj.options.classes[k[i]]); } } } /** * Refresh the data * * @return void */ obj.refresh = function() { if (obj.options.url) { // Loading if (obj.options.loadingSpin == true) { jSuites.loading.show(); } jSuites.ajax({ url: obj.options.url, method: obj.options.method, data: obj.options.requestVariables, dataType: 'json', success: function(result) { // Data obj.options.data = (result.data) ? result.data : result; // Prepare table obj.setData(); // Hide spin if (obj.options.loadingSpin == true) { jSuites.loading.hide(); } } }); } else { obj.setData(); } } /** * Set data * * @param array data In case no data is sent, default is reloaded * @return void */ obj.setData = function(data) { // Update data if (data) { if (typeof(data) == 'string') { data = JSON.parse(data); } obj.options.data = data; } // Data if (! obj.options.data) { obj.options.data = []; } // Prepare data if (obj.options.data && obj.options.data[0]) { if (! Array.isArray(obj.options.data[0])) { var data = []; for (var j = 0; j < obj.options.data.length; j++) { var row = []; for (var i = 0; i < obj.options.columns.length; i++) { row[i] = obj.options.data[j][obj.options.columns[i].name]; } data.push(row); } obj.options.data = data; } } // Adjust minimal dimensions var j = 0; var i = 0; var size_i = obj.options.columns.length; var size_j = obj.options.data.length; var min_i = obj.options.minDimensions[0]; var min_j = obj.options.minDimensions[1]; var max_i = min_i > size_i ? min_i : size_i; var max_j = min_j > size_j ? min_j : size_j; for (j = 0; j < max_j; j++) { for (i = 0; i < max_i; i++) { if (obj.options.data[j] == undefined) { obj.options.data[j] = []; } if (obj.options.data[j][i] == undefined) { obj.options.data[j][i] = ''; } } } // Reset containers obj.rows = []; obj.results = null; obj.records = []; obj.history = []; // Reset internal controllers obj.historyIndex = -1; // Reset data obj.tbody.innerHTML = ''; // Lazy loading if (obj.options.lazyLoading == true) { // Load only 100 records var startNumber = 0 var finalNumber = obj.options.data.length < 100 ? obj.options.data.length : 100; if (obj.options.pagination) { obj.options.pagination = false; console.error('Jspreadsheet: Pagination will be disable due the lazyLoading'); } } else if (obj.options.pagination) { // Pagination if (! obj.pageNumber) { obj.pageNumber = 0; } var quantityPerPage = obj.options.pagination; startNumber = (obj.options.pagination * obj.pageNumber); finalNumber = (obj.options.pagination * obj.pageNumber) + obj.options.pagination; if (obj.options.data.length < finalNumber) { finalNumber = obj.options.data.length; } } else { var startNumber = 0; var finalNumber = obj.options.data.length; } // Append nodes to the HTML for (j = 0; j < obj.options.data.length; j++) { // Create row var tr = obj.createRow(j, obj.options.data[j]); // Append line to the table if (j >= startNumber && j < finalNumber) { obj.tbody.appendChild(tr); } } if (obj.options.lazyLoading == true) { // Do not create pagination with lazyloading activated } else if (obj.options.pagination) { obj.updatePagination(); } // Merge cells if (obj.options.mergeCells) { var keys = Object.keys(obj.options.mergeCells); for (var i = 0; i < keys.length; i++) { var num = obj.options.mergeCells[keys[i]]; obj.setMerge(keys[i], num[0], num[1], 1); } } // Updata table with custom configurations if applicable obj.updateTable(); // Onload obj.dispatch('onload', el, obj); } /** * Get the whole table data * * @param bool get highlighted cells only * @return array data */ obj.getData = function(highlighted, dataOnly) { // Control vars var dataset = []; var px = 0; var py = 0; // Data type var dataType = dataOnly == true || obj.options.copyCompatibility == false ? true : false; // Column and row length var x = obj.options.columns.length var y = obj.options.data.length // Go through the columns to get the data for (var j = 0; j < y; j++) { px = 0; for (var i = 0; i < x; i++) { // Cell selected or fullset if (! highlighted || obj.records[j][i].classList.contains('highlight')) { // Get value if (! dataset[py]) { dataset[py] = []; } if (! dataType) { dataset[py][px] = obj.records[j][i].innerHTML; } else { dataset[py][px] = obj.options.data[j][i]; } px++; } } if (px > 0) { py++; } } return dataset; } /** * Get json data by row number * * @param integer row number * @return object */ obj.getJsonRow = function(rowNumber) { var rowData = obj.options.data[rowNumber]; var x = obj.options.columns.length var row = {}; for (var i = 0; i < x; i++) { if (! obj.options.columns[i].name) { obj.options.columns[i].name = i; } row[obj.options.columns[i].name] = rowData[i]; } return row; } /** * Get the whole table data * * @param bool highlighted cells only * @return string value */ obj.getJson = function(highlighted) { // Control vars var data = []; // Column and row length var x = obj.options.columns.length var y = obj.options.data.length // Go through the columns to get the data for (var j = 0; j < y; j++) { var row = null; for (var i = 0; i < x; i++) { if (! highlighted || obj.records[j][i].classList.contains('highlight')) { if (row == null) { row = {}; } if (! obj.options.columns[i].name) { obj.options.columns[i].name = i; } row[obj.options.columns[i].name] = obj.options.data[j][i]; } } if (row != null) { data.push(row); } } return data; } /** * Prepare JSON in the correct format */ obj.prepareJson = function(data) { var rows = []; for (var i = 0; i < data.length; i++) { var x = data[i].x; var y = data[i].y; var k = obj.options.columns[x].name ? obj.options.columns[x].name : x; // Create row if (! rows[y]) { rows[y] = { row: y, data: {}, }; } rows[y].data[k] = data[i].newValue; } // Filter rows return rows.filter(function (el) { return el != null; }); } /** * Post json to a remote server */ obj.save = function(url, data) { // Parse anything in the data before sending to the server var ret = obj.dispatch('onbeforesave', el, obj, data); if (ret) { var data = ret; } else { if (ret === false) { return false; } } // Remove update jSuites.ajax({ url: url, method: 'POST', dataType: 'json', data: { data: JSON.stringify(data) }, success: function(result) { // Event obj.dispatch('onsave', el, obj, data); } }); } /** * Get a row data by rowNumber */ obj.getRowData = function(rowNumber) { return obj.options.data[rowNumber]; } /** * Set a row data by rowNumber */ obj.setRowData = function(rowNumber, data) { for (var i = 0; i < obj.headers.length; i++) { // Update cell var columnName = jexcel.getColumnNameFromId([ i, rowNumber ]); // Set value if (data[i] != null) { obj.setValue(columnName, data[i]); } } } /** * Get a column data by columnNumber */ obj.getColumnData = function(columnNumber) { var dataset = []; // Go through the rows to get the data for (var j = 0; j < obj.options.data.length; j++) { dataset.push(obj.options.data[j][columnNumber]); } return dataset; } /** * Set a column data by colNumber */ obj.setColumnData = function(colNumber, data) { for (var j = 0; j < obj.rows.length; j++) { // Update cell var columnName = jexcel.getColumnNameFromId([ colNumber, j ]); // Set value if (data[j] != null) { obj.setValue(columnName, data[j]); } } } /** * Create row */ obj.createRow = function(j, data) { // Create container if (! obj.records[j]) { obj.records[j] = []; } // Default data if (! data) { var data = obj.options.data[j]; } // New line of data to be append in the table obj.rows[j] = document.createElement('tr'); obj.rows[j].setAttribute('data-y', j); // Index var index = null; // Definitions if (obj.options.rows[j]) { if (obj.options.rows[j].height) { obj.rows[j].style.height = obj.options.rows[j].height; } if (obj.options.rows[j].title) { index = obj.options.rows[j].title; } } if (! index) { index = parseInt(j + 1); } // Row number label var td = document.createElement('td'); td.innerHTML = index; td.setAttribute('data-y', j); td.className = 'jexcel_row'; obj.rows[j].appendChild(td); // Data columns for (var i = 0; i < obj.options.columns.length; i++) { // New column of data to be append in the line obj.records[j][i] = obj.createCell(i, j, data[i]); // Add column to the row obj.rows[j].appendChild(obj.records[j][i]); } // Add row to the table body return obj.rows[j]; } obj.parseValue = function(i, j, value) { if ((''+value).substr(0,1) == '=' && obj.options.parseFormulas == true) { value = obj.executeFormula(value, i, j) } if (obj.options.columns[i].mask) { var decimal = obj.options.columns[i].decimal || '.'; value = '' + jSuites.mask.run(value, obj.options.columns[i].mask, decimal); } return value; } /** * Create cell */ obj.createCell = function(i, j, value) { // Create cell and properties var td = document.createElement('td'); td.setAttribute('data-x', i); td.setAttribute('data-y', j); // Security if ((''+value).substr(0,1) == '=' && obj.options.secureFormulas == true) { var val = secureFormula(value); if (val != value) { // Update the data container value = val; } } // Custom column if (obj.options.columns[i].editor) { if (obj.options.stripHTML === false || obj.options.columns[i].stripHTML === false) { td.innerHTML = value; } else { td.innerText = value; } if (typeof(obj.options.columns[i].editor.createCell) == 'function') { td = obj.options.columns[i].editor.createCell(td); } } else { // Hidden column if (obj.options.columns[i].type == 'hidden') { td.style.display = 'none'; td.innerText = value; } else if (obj.options.columns[i].type == 'checkbox' || obj.options.columns[i].type == 'radio') { // Create input var element = document.createElement('input'); element.type = obj.options.columns[i].type; element.name = 'c' + i; element.checked = (value == 1 || value == true || value == 'true') ? true : false; element.onclick = function() { obj.setValue(td, this.checked); } if (obj.options.columns[i].readOnly == true || obj.options.editable == false) { element.setAttribute('disabled', 'disabled'); } // Append to the table td.appendChild(element); // Make sure the values are correct obj.options.data[j][i] = element.checked; } else if (obj.options.columns[i].type == 'calendar') { // Try formatted date var formatted = jSuites.calendar.extractDateFromString(value, obj.options.columns[i].options.format); // Create calendar cell td.innerText = jSuites.calendar.getDateString(formatted ? formatted : value, obj.options.columns[i].options.format); } else if (obj.options.columns[i].type == 'dropdown' || obj.options.columns[i].type == 'autocomplete') { // Create dropdown cell td.classList.add('jexcel_dropdown'); td.innerText = obj.getDropDownValue(i, value); } else if (obj.options.columns[i].type == 'color') { if (obj.options.columns[i].render == 'square') { var color = document.createElement('div'); color.className = 'color'; color.style.backgroundColor = value; td.appendChild(color); } else { td.style.color = value; td.innerText = value; } } else if (obj.options.columns[i].type == 'image') { if (value && value.substr(0, 10) == 'data:image') { var img = document.createElement('img'); img.src = value; td.appendChild(img); } } else { if (obj.options.columns[i].type == 'html') { td.innerHTML = stripScript(obj.parseValue(i, j, value)); } else { if (obj.options.stripHTML === false || obj.options.columns[i].stripHTML === false) { td.innerHTML = stripScript(obj.parseValue(i, j, value)); } else { td.innerText = obj.parseValue(i, j, value); } } } } // Readonly if (obj.options.columns[i].readOnly == true) { td.className = 'readonly'; } // Text align var colAlign = obj.options.columns[i].align ? obj.options.columns[i].align : 'center'; td.style.textAlign = colAlign; // Wrap option if (obj.options.columns[i].wordWrap != false && (obj.options.wordWrap == true || obj.options.columns[i].wordWrap == true || td.innerHTML.length > 200)) { td.style.whiteSpace = 'pre-wrap'; } // Overflow if (i > 0) { if (this.options.textOverflow == true) { if (value || td.innerHTML) { obj.records[j][i-1].style.overflow = 'hidden'; } else { if (i == obj.options.columns.length - 1) { td.style.overflow = 'hidden'; } } } } return td; } obj.createCellHeader = function(colNumber) { // Create col global control var colWidth = obj.options.columns[colNumber].width ? obj.options.columns[colNumber].width : obj.options.defaultColWidth; var colAlign = obj.options.columns[colNumber].align ? obj.options.columns[colNumber].align : obj.options.defaultColAlign; // Create header cell obj.headers[colNumber] = document.createElement('td'); if (obj.options.stripHTML) { obj.headers[colNumber].innerText = obj.options.columns[colNumber].title ? obj.options.columns[colNumber].title :