Move buildCssRule to utils, focus and edit cell functionality

This commit is contained in:
Faris Ansari 2017-10-01 12:32:02 +05:30
parent f2177f96ed
commit fa6a582a45
6 changed files with 286 additions and 193 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,11 +3,10 @@ import {
getBodyHTML,
getRowHTML,
getColumnHTML,
getEditCellHTML,
prepareRowHeader,
buildCSSRule,
prepareRows,
getDefault,
escapeRegExp
getDefault
} from './utils.js';
import $ from 'jQuery';
import Clusterize from 'clusterize.js';
@ -220,15 +219,7 @@ export default class ReGrid {
}
bindEvents() {
const self = this;
this.bodyScrollable.on('click', '.data-table-col', function () {
const $col = $(this);
self.bodyScrollable.find('.data-table-col').removeClass('selected');
$col.addClass('selected');
});
this.bindFocusCell();
this.bindEditCell();
this.bindResizeColumn();
this.bindSortColumn();
@ -269,40 +260,36 @@ export default class ReGrid {
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() {
const self = this;
const $editPopup = this.wrapper.find('.edit-popup');
$editPopup.hide();
this.$editingCell = null;
// if (!self.events.onCellEdit) return;
this.bodyScrollable.on('dblclick', '.data-table-col', function () {
const $cell = $(this);
const rowIndex = $cell.attr('data-row-index');
const colIndex = $cell.attr('data-col-index');
const $editCell = $cell.find('.edit-cell');
self.activateEditing($(this));
});
const cell = self.getCell(rowIndex, colIndex);
$editCell.find('input').val(cell.content);
// $editPopup.html(getEditCellHTML(cellValue.content));
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('keypress', (e) => {
// enter keypress on focused cell
if (e.which === 13 && this.$focusedCell) {
self.activateEditing(this.$focusedCell);
}
});
$(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() {
const self = this;
let isDragging = false;
@ -416,9 +423,14 @@ export default class ReGrid {
}
setColumnWidth(colIndex, width) {
// set width for content
this.setStyle(`[data-col-index="${colIndex}"] .content`, {
width: width + 'px'
});
// set width for edit cell
this.setStyle(`[data-col-index="${colIndex}"] .edit-cell`, {
width: width + 'px'
});
}
setRowHeight(rowIndex, height) {
@ -475,58 +487,12 @@ export default class ReGrid {
setStyle(rule, styleMap) {
this.getStyleEl();
const self = this;
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);
}
getCSSString(styleMap) {
let style = '';
for (const prop in styleMap) {
if (styleMap.hasOwnProperty(prop)) {
style += `${prop}: ${styleMap[prop]};`;
}
}
console.log(style);
return style;
}
getStyleEl() {
if (!this.$style) {
this.$style = $('<style data-id="regrid"></style>')
@ -565,6 +531,10 @@ export default class ReGrid {
return this.minWidthMap && this.minWidthMap[colIndex];
}
getCellAttr($cell) {
return $cell.data();
}
log() {
if (this.enableLogs) {
console.log.apply(console, arguments);

View File

@ -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 {
position: absolute;
top: -1px;
left: -1px;
background: white;
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
z-index: 1;
input {

View File

@ -127,6 +127,61 @@ function escapeRegExp(str) {
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 {
getHeaderHTML,
getBodyHTML,
@ -135,6 +190,9 @@ export default {
getEditCellHTML,
prepareRowHeader,
prepareRows,
namespaceSelector,
getCSSString,
buildCSSRule,
makeDataAttributeString,
getDefault,
escapeRegExp

View File

@ -2,7 +2,9 @@
import chai from 'chai';
import {
makeDataAttributeString
makeDataAttributeString,
getCSSString,
buildCSSRule,
} from '../src/utils.js';
chai.expect();
@ -21,4 +23,48 @@ describe('#utils', () => {
.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; }');
});
});
});