Move buildCssRule to utils, focus and edit cell functionality
This commit is contained in:
parent
f2177f96ed
commit
fa6a582a45
216
lib/ReGrid.js
216
lib/ReGrid.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
138
src/regrid.js
138
src/regrid.js
@ -3,11 +3,10 @@ import {
|
|||||||
getBodyHTML,
|
getBodyHTML,
|
||||||
getRowHTML,
|
getRowHTML,
|
||||||
getColumnHTML,
|
getColumnHTML,
|
||||||
getEditCellHTML,
|
|
||||||
prepareRowHeader,
|
prepareRowHeader,
|
||||||
|
buildCSSRule,
|
||||||
prepareRows,
|
prepareRows,
|
||||||
getDefault,
|
getDefault
|
||||||
escapeRegExp
|
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import $ from 'jQuery';
|
import $ from 'jQuery';
|
||||||
import Clusterize from 'clusterize.js';
|
import Clusterize from 'clusterize.js';
|
||||||
@ -220,15 +219,7 @@ export default class ReGrid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bindEvents() {
|
bindEvents() {
|
||||||
const self = this;
|
this.bindFocusCell();
|
||||||
|
|
||||||
this.bodyScrollable.on('click', '.data-table-col', function () {
|
|
||||||
const $col = $(this);
|
|
||||||
|
|
||||||
self.bodyScrollable.find('.data-table-col').removeClass('selected');
|
|
||||||
$col.addClass('selected');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.bindEditCell();
|
this.bindEditCell();
|
||||||
this.bindResizeColumn();
|
this.bindResizeColumn();
|
||||||
this.bindSortColumn();
|
this.bindSortColumn();
|
||||||
@ -269,40 +260,36 @@ export default class ReGrid {
|
|||||||
this.bodyScrollable.find('.table').css('margin', 0);
|
this.bodyScrollable.find('.table').css('margin', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindFocusCell() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
this.$focusedCell = null;
|
||||||
|
this.bodyScrollable.on('click', '.data-table-col', function () {
|
||||||
|
const $cell = $(this);
|
||||||
|
|
||||||
|
self.$focusedCell = $cell;
|
||||||
|
self.bodyScrollable.find('.data-table-col').removeClass('selected');
|
||||||
|
$cell.addClass('selected');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bindEditCell() {
|
bindEditCell() {
|
||||||
const self = this;
|
const self = this;
|
||||||
const $editPopup = this.wrapper.find('.edit-popup');
|
const $editPopup = this.wrapper.find('.edit-popup');
|
||||||
|
|
||||||
$editPopup.hide();
|
$editPopup.hide();
|
||||||
|
this.$editingCell = null;
|
||||||
// if (!self.events.onCellEdit) return;
|
// if (!self.events.onCellEdit) return;
|
||||||
|
|
||||||
this.bodyScrollable.on('dblclick', '.data-table-col', function () {
|
this.bodyScrollable.on('dblclick', '.data-table-col', function () {
|
||||||
const $cell = $(this);
|
self.activateEditing($(this));
|
||||||
const rowIndex = $cell.attr('data-row-index');
|
});
|
||||||
const colIndex = $cell.attr('data-col-index');
|
|
||||||
const $editCell = $cell.find('.edit-cell');
|
|
||||||
|
|
||||||
const cell = self.getCell(rowIndex, colIndex);
|
$(document.body).on('keypress', (e) => {
|
||||||
|
// enter keypress on focused cell
|
||||||
$editCell.find('input').val(cell.content);
|
if (e.which === 13 && this.$focusedCell) {
|
||||||
// $editPopup.html(getEditCellHTML(cellValue.content));
|
self.activateEditing(this.$focusedCell);
|
||||||
|
}
|
||||||
const width = $cell.find('.content').width() + 1;
|
|
||||||
const height = $cell.find('.content').height() + 1;
|
|
||||||
|
|
||||||
const selector = `.data-table .body-scrollable [data-row-index="${rowIndex}"][data-row-index="${rowIndex}"] .edit-cell`;
|
|
||||||
|
|
||||||
self.setStyle(selector, { width, height });
|
|
||||||
$editCell.show();
|
|
||||||
$editCell.find('input').select();
|
|
||||||
|
|
||||||
// showing the popup is the responsibility of event handler
|
|
||||||
// self.events.onCellEdit(
|
|
||||||
// $cell.get(0),
|
|
||||||
// $editPopup,
|
|
||||||
// rowIndex,
|
|
||||||
// colIndex
|
|
||||||
// );
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document.body).on('click', e => {
|
$(document.body).on('click', e => {
|
||||||
@ -311,6 +298,26 @@ export default class ReGrid {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activateEditing($cell) {
|
||||||
|
const rowIndex = $cell.attr('data-row-index');
|
||||||
|
const colIndex = $cell.attr('data-col-index');
|
||||||
|
const $editCell = $cell.find('.edit-cell');
|
||||||
|
const cell = this.getCell(rowIndex, colIndex);
|
||||||
|
|
||||||
|
this.$editingCell = $cell;
|
||||||
|
$editCell.find('input').val(cell.content);
|
||||||
|
$editCell.show();
|
||||||
|
$editCell.find('input').select();
|
||||||
|
|
||||||
|
// showing the popup is the responsibility of event handler
|
||||||
|
// self.events.onCellEdit(
|
||||||
|
// $cell.get(0),
|
||||||
|
// $editPopup,
|
||||||
|
// rowIndex,
|
||||||
|
// colIndex
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
bindResizeColumn() {
|
bindResizeColumn() {
|
||||||
const self = this;
|
const self = this;
|
||||||
let isDragging = false;
|
let isDragging = false;
|
||||||
@ -416,9 +423,14 @@ export default class ReGrid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setColumnWidth(colIndex, width) {
|
setColumnWidth(colIndex, width) {
|
||||||
|
// set width for content
|
||||||
this.setStyle(`[data-col-index="${colIndex}"] .content`, {
|
this.setStyle(`[data-col-index="${colIndex}"] .content`, {
|
||||||
width: width + 'px'
|
width: width + 'px'
|
||||||
});
|
});
|
||||||
|
// set width for edit cell
|
||||||
|
this.setStyle(`[data-col-index="${colIndex}"] .edit-cell`, {
|
||||||
|
width: width + 'px'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setRowHeight(rowIndex, height) {
|
setRowHeight(rowIndex, height) {
|
||||||
@ -475,58 +487,12 @@ export default class ReGrid {
|
|||||||
|
|
||||||
setStyle(rule, styleMap) {
|
setStyle(rule, styleMap) {
|
||||||
this.getStyleEl();
|
this.getStyleEl();
|
||||||
const self = this;
|
|
||||||
let styles = this.$style.text();
|
let styles = this.$style.text();
|
||||||
const rulePatternStr = `${escapeRegExp(rule)} {([^}]*)}`;
|
|
||||||
const rulePattern = new RegExp(rulePatternStr, 'g');
|
|
||||||
|
|
||||||
if (styles.match(rulePattern)) {
|
|
||||||
// rules exists, append/replace properties
|
|
||||||
|
|
||||||
for (const property in styleMap) {
|
|
||||||
const value = styleMap[property];
|
|
||||||
|
|
||||||
const propPattern = new RegExp(`${escapeRegExp(property)}[^;]*;`);
|
|
||||||
|
|
||||||
styles = styles.replace(rulePattern, function (match, propertyStr) {
|
|
||||||
if (propertyStr.match(propPattern)) {
|
|
||||||
// property exists, replace with empty string
|
|
||||||
propertyStr = propertyStr.replace(propPattern, '');
|
|
||||||
}
|
|
||||||
propertyStr = propertyStr.trim();
|
|
||||||
|
|
||||||
const _styleMap = {};
|
|
||||||
|
|
||||||
_styleMap[property] = value;
|
|
||||||
const replacer =
|
|
||||||
`${rule} {${propertyStr}${self.getCSSString(_styleMap)}}`;
|
|
||||||
|
|
||||||
return replacer;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// rules doesn't exists, add rule with properties
|
|
||||||
styles += `${rule} {${styleMap}}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
styles = buildCSSRule(rule, styleMap, styles);
|
||||||
this.$style.html(styles);
|
this.$style.html(styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCSSString(styleMap) {
|
|
||||||
let style = '';
|
|
||||||
|
|
||||||
for (const prop in styleMap) {
|
|
||||||
if (styleMap.hasOwnProperty(prop)) {
|
|
||||||
style += `${prop}: ${styleMap[prop]};`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(style);
|
|
||||||
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
getStyleEl() {
|
getStyleEl() {
|
||||||
if (!this.$style) {
|
if (!this.$style) {
|
||||||
this.$style = $('<style data-id="regrid"></style>')
|
this.$style = $('<style data-id="regrid"></style>')
|
||||||
@ -565,6 +531,10 @@ export default class ReGrid {
|
|||||||
return this.minWidthMap && this.minWidthMap[colIndex];
|
return this.minWidthMap && this.minWidthMap[colIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCellAttr($cell) {
|
||||||
|
return $cell.data();
|
||||||
|
}
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
if (this.enableLogs) {
|
if (this.enableLogs) {
|
||||||
console.log.apply(console, arguments);
|
console.log.apply(console, arguments);
|
||||||
|
|||||||
@ -61,28 +61,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-popup {
|
|
||||||
position: absolute;
|
|
||||||
background: white;
|
|
||||||
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
|
||||||
|
|
||||||
input {
|
|
||||||
outline: none;
|
|
||||||
padding: 8px;
|
|
||||||
font-size: inherit;
|
|
||||||
font-family: inherit;
|
|
||||||
width: inherit;
|
|
||||||
height: inherit;
|
|
||||||
border: 2px solid theme-color('primary');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-cell {
|
.edit-cell {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
left: -1px;
|
left: -1px;
|
||||||
background: white;
|
background: white;
|
||||||
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
|||||||
58
src/utils.js
58
src/utils.js
@ -127,6 +127,61 @@ function escapeRegExp(str) {
|
|||||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCSSString(styleMap) {
|
||||||
|
let style = '';
|
||||||
|
|
||||||
|
for (const prop in styleMap) {
|
||||||
|
if (styleMap.hasOwnProperty(prop)) {
|
||||||
|
style += `${prop}: ${styleMap[prop]}; `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return style.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSSRuleBlock(rule, styleMap) {
|
||||||
|
return `${rule} { ${getCSSString(styleMap)} }`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function namespaceSelector(selector) {
|
||||||
|
return '.data-table ' + selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCSSRule(rule, styleMap, cssRulesString = '') {
|
||||||
|
// build css rules efficiently,
|
||||||
|
// append new rule if doesnt exist,
|
||||||
|
// update existing ones
|
||||||
|
|
||||||
|
const rulePatternStr = `${escapeRegExp(rule)} {([^}]*)}`;
|
||||||
|
const rulePattern = new RegExp(rulePatternStr, 'g');
|
||||||
|
|
||||||
|
if (cssRulesString && cssRulesString.match(rulePattern)) {
|
||||||
|
for (const property in styleMap) {
|
||||||
|
const value = styleMap[property];
|
||||||
|
const propPattern = new RegExp(`${escapeRegExp(property)}:([^;]*);`);
|
||||||
|
|
||||||
|
cssRulesString = cssRulesString.replace(rulePattern, function (match, propertyStr) {
|
||||||
|
if (propertyStr.match(propPattern)) {
|
||||||
|
// property exists, replace value with new value
|
||||||
|
propertyStr = propertyStr.replace(propPattern, (match, valueStr) => {
|
||||||
|
return `${property}: ${value};`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
propertyStr = propertyStr.trim();
|
||||||
|
|
||||||
|
const replacer =
|
||||||
|
`${rule} { ${propertyStr} }`;
|
||||||
|
|
||||||
|
return replacer;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return cssRulesString;
|
||||||
|
}
|
||||||
|
// no match, append new rule block
|
||||||
|
return `${cssRulesString}${getCSSRuleBlock(rule, styleMap)}`;
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getHeaderHTML,
|
getHeaderHTML,
|
||||||
getBodyHTML,
|
getBodyHTML,
|
||||||
@ -135,6 +190,9 @@ export default {
|
|||||||
getEditCellHTML,
|
getEditCellHTML,
|
||||||
prepareRowHeader,
|
prepareRowHeader,
|
||||||
prepareRows,
|
prepareRows,
|
||||||
|
namespaceSelector,
|
||||||
|
getCSSString,
|
||||||
|
buildCSSRule,
|
||||||
makeDataAttributeString,
|
makeDataAttributeString,
|
||||||
getDefault,
|
getDefault,
|
||||||
escapeRegExp
|
escapeRegExp
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
import chai from 'chai';
|
import chai from 'chai';
|
||||||
import {
|
import {
|
||||||
makeDataAttributeString
|
makeDataAttributeString,
|
||||||
|
getCSSString,
|
||||||
|
buildCSSRule,
|
||||||
} from '../src/utils.js';
|
} from '../src/utils.js';
|
||||||
|
|
||||||
chai.expect();
|
chai.expect();
|
||||||
@ -21,4 +23,48 @@ describe('#utils', () => {
|
|||||||
.to.be.equal('data-is-header="1" data-col-index="0" data-row-index="4"');
|
.to.be.equal('data-is-header="1" data-col-index="0" data-row-index="4"');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getCSSString', () => {
|
||||||
|
it('should return CSS key value pairs', () => {
|
||||||
|
const style = {
|
||||||
|
width: '2px',
|
||||||
|
height: '4px',
|
||||||
|
'margin-top': '3px'
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getCSSString(style))
|
||||||
|
.to.be.equal('width: 2px; height: 4px; margin-top: 3px;');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('buildCSSRule', () => {
|
||||||
|
it('should return CSS rule string with updated properties', () => {
|
||||||
|
const rule = '.test';
|
||||||
|
const style = {
|
||||||
|
width: '2px',
|
||||||
|
height: '4px',
|
||||||
|
'margin-top': '3px'
|
||||||
|
};
|
||||||
|
|
||||||
|
const ruleString = buildCSSRule(rule, style);
|
||||||
|
|
||||||
|
expect(ruleString)
|
||||||
|
.to.be.equal('.test { width: 2px; height: 4px; margin-top: 3px; }');
|
||||||
|
|
||||||
|
const updatedRuleString = buildCSSRule(rule, { width: '5px' }, ruleString);
|
||||||
|
|
||||||
|
expect(updatedRuleString)
|
||||||
|
.to.be.equal('.test { width: 5px; height: 4px; margin-top: 3px; }');
|
||||||
|
|
||||||
|
const updatedRuleString2 = buildCSSRule(rule, { height: '19px' }, updatedRuleString);
|
||||||
|
|
||||||
|
expect(updatedRuleString2)
|
||||||
|
.to.be.equal('.test { width: 5px; height: 19px; margin-top: 3px; }');
|
||||||
|
|
||||||
|
const updatedRuleString3 = buildCSSRule('.test2', { height: '45px' }, updatedRuleString2);
|
||||||
|
|
||||||
|
expect(updatedRuleString3)
|
||||||
|
.to.be.equal('.test { width: 5px; height: 19px; margin-top: 3px; }.test2 { height: 45px; }');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user