Skip to content

Commit

Permalink
feat: add FEEL editor for table cells
Browse files Browse the repository at this point in the history
Closes #774
  • Loading branch information
barmac committed Sep 22, 2023
1 parent 6799d52 commit d4e02b0
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,18 @@
width: 20px;
right: 0;
}

/* cell editor */
.dmn-decision-table-container .cell-editor__placeholder {
position: absolute;
}

.dmn-decision-table-container .cell-editor:focus-within .cell-editor__placeholder,
.dmn-decision-table-container .cell-editor:focus-within .dmn-expression-language {
display: none;
}

.dmn-decision-table-container .cell-editor,
.dmn-decision-table-container .cell-editor .cm-scroller {
line-height: normal;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import {
import cssEscape from 'css.escape';

import {
setRange,
getRange
} from 'selection-ranges';

export const SELECTABLE_SELECTOR = '[contenteditable]';
export const SELECTABLE_SELECTOR = [
'[contenteditable]',
'[tabindex]:not([tabindex="-1"])',
'input',
'textarea'
].join(',');

export const ELEMENT_SELECTOR = '[data-element-id]';

Expand Down Expand Up @@ -109,6 +113,6 @@ export function ensureFocus(el) {
const range = getRange(focusEl);

if (!range || range.end === 0) {
setRange(focusEl, { start: 5000, end: 5000 });
window.getSelection().setPosition(focusEl.firstChild, focusEl.firstChild.length);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { isString } from 'min-dash';

import { is } from 'dmn-js-shared/lib/util/ModelUtil';

import EditableComponent from 'dmn-js-shared/lib/components/EditableComponent';
import ContentEditable from 'dmn-js-shared/lib/components/ContentEditable';
import LiteralExpression from 'dmn-js-shared/lib/components/LiteralExpression';

import { Cell } from 'table-js/lib/components';

Expand All @@ -14,22 +15,14 @@ export default class DecisionRulesCellEditorComponent extends Component {
constructor(props, context) {
super(props, context);

this.state = {
isFocussed: false
};

this.changeCellValue = this.changeCellValue.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onElementsChanged = this.onElementsChanged.bind(this);
}


onElementsChanged() {
this.forceUpdate();
}


componentWillMount() {
const { injector } = this.context;

Expand All @@ -42,35 +35,18 @@ export default class DecisionRulesCellEditorComponent extends Component {
changeSupport.onElementsChanged(cell.id, this.onElementsChanged);
}


componentWillUnmount() {
const { cell } = this.props;

this._changeSupport.offElementsChanged(cell.id, this.onElementsChanged);
}


changeCellValue(value) {
const { cell } = this.props;

this._modeling.editCell(cell.businessObject, value);
}


onFocus() {
this.setState({
isFocussed: true
});
}


onBlur() {
this.setState({
isFocussed: false
});
}


render() {
const {
cell,
Expand All @@ -80,8 +56,6 @@ export default class DecisionRulesCellEditorComponent extends Component {
colIndex
} = this.props;

const { isFocussed } = this.state;

const isUnaryTest = is(cell, 'dmn:UnaryTests');
const businessObject = cell.businessObject;

Expand All @@ -94,12 +68,7 @@ export default class DecisionRulesCellEditorComponent extends Component {
data-col-id={ col.id }
>
<TableCellEditor
className="cell-editor"
placeholder={ isUnaryTest ? '-' : '' }
ctrlForNewline={ true }
onFocus={ this.onFocus }
onBlur={ this.onBlur }
isFocussed={ isFocussed }
onChange={ this.changeCellValue }
value={ businessObject.text }
businessObject={ businessObject } />
Expand All @@ -108,8 +77,42 @@ export default class DecisionRulesCellEditorComponent extends Component {
}
}

class FeelEditor extends Component {
constructor(props, context) {
super(props, context);
this.state = { focussed: false };

class TableCellEditor extends EditableComponent {
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
}

onFocus() {
this.setState({ focussed: true });
}

onBlur() {
this.setState({ focussed: false });
}

render() {
if (this.state.focussed) {
return <LiteralExpression
{ ...this.props }
autoFocus={ true }
onBlur={ this.onBlur }
/>;
}

return <div onClick={ this.onFocus }>
<ContentEditable
{ ...this.props }
onFocus={ this.onFocus }
/>
</div>;
}
}

class TableCellEditor extends Component {

constructor(props, context) {
super(props, context);
Expand Down Expand Up @@ -164,10 +167,27 @@ class TableCellEditor extends EditableComponent {
return this._expressionLanguages.getDefault(elementType);
}

getEditor() {
return this.isFEEL() ? FeelEditor : ContentEditable;
}

isFEEL() {
return this.getExpressionLanguage() === 'feel';
}

getExpressionLanguage() {
const { businessObject } = this.props;

return businessObject.expressionLanguage ||
this.getDefaultExpressionLanguage(businessObject).value;
}

render() {
const {
businessObject,
isFocussed
placeholder,
value,
onChange
} = this.props;

const description = this.getDescription(businessObject);
Expand All @@ -178,21 +198,23 @@ class TableCellEditor extends EditableComponent {

const isScript = this.isScript(businessObject);

const Editor = this.getEditor();

return (
<div className={ this.getClassName() }>
<div className="cell-editor">
{
isString(description)
&& !isFocussed
&& <div className="description-indicator"></div>
}
<Editor
className={ isScript ? 'script-editor' : null }
ctrlForNewline={ true }
onInput={ onChange }
value={ value }
placeholder={ placeholder }
/>
{
this.getEditor({
className: isScript ? 'script-editor' : null
})
}
{
!isDefaultExpressionLanguage &&
!isFocussed && (
!isDefaultExpressionLanguage && (
<span
className="dms-badge dmn-expression-language"
title={ this._translate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default class Keyboard {
this._node = node;

// bind key events
domEvent.bind(node, 'keydown', this._keyHandler, true);
domEvent.bind(node, 'keydown', this._keyHandler);

this._fire('bind');
}
Expand All @@ -118,7 +118,7 @@ export default class Keyboard {
this._fire('unbind');

// unbind key events
domEvent.unbind(node, 'keydown', this._keyHandler, true);
domEvent.unbind(node, 'keydown', this._keyHandler);
}

this._node = null;
Expand Down
14 changes: 14 additions & 0 deletions packages/dmn-js-decision-table/test/helper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,17 @@ export function insertCSS(name, css) {

head.appendChild(style);
}

/**
* Execute function and resolve in next frame.
*
* @param {Function} fn
*/
export function act(fn) {
fn();
return new Promise(resolve => {
requestAnimationFrame(() => {
resolve();
});
});
}
12 changes: 6 additions & 6 deletions packages/dmn-js-decision-table/test/spec/EditorSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ describe('DecisionTable', function() {

let dmnJS;

afterEach(function() {
if (dmnJS) {
dmnJS.destroy();
dmnJS = null;
}
});
// afterEach(function() {
// if (dmnJS) {
// dmnJS.destroy();
// dmnJS = null;
// }
// });

beforeEach(function() {
testContainer = TestContainer.get(this);
Expand Down
Loading

0 comments on commit d4e02b0

Please sign in to comment.