I am trying to implement the summernote rich text editor in handsontable. The requirement is like when user press enter/F2/double click on a cell then the Rich text editor should open and cursor should move to editor having cell text in the editor(if cell keeps any data) and user can enter/modify the data. The user can modify data (can make bold/italic/upload image etc) with the help of editor toolbar. After entering or modifying data it should be back to populate in the handsontable cell as per the default behavior of handsontable.
I have tried to implement the above behavior in handsontable using summernote. I am able to open the editor after pressing enter key in cell but the summernote editor gets freezes for a while and focus in the editor is not coming to enter any data.
Please suggest/help to integrate summernote in handsontable.
Here is the complete html page:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handsontable/0.22.0/handsontable.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/handsontable/0.22.0/handsontable.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.0/summernote.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.0/summernote.css" rel="stylesheet" />
<style type="text/css">
body {
background: white;
margin: 20px;
}
h2 {
margin: 20px 0;
}
</style>
</head>
<body>
<div id="example_handsontable" class="handsontable"></div>
<!--Selected Id: <span id="selectedId"></span>-->
<div class="summernote"></div>
</body>
<script type="text/javascript">
$(document).ready(function () {
var mydata = [{ num: 1, num2: 2, num3: 3 }
, { num: 1, num2: 2, num3: 3 }
, { num: 1, num2: 2, num3: 3 }
, { num: 1, num2: 2, num3: 3 }
, { num: 1, num2: 2, num3: 3 }
, { num: 1, num2: 2, num3: 3 }];
var columnsList =
[{
data: 'num',
editor: 'summernote',
renderer: summerNoteRenderer,
width: '200px'
},
{
data: 'num',
editor: 'summernote',
renderer: summerNoteRenderer,
width: '200px'
},
{
data: 'num',
editor: 'summernote',
renderer: summerNoteRenderer,
width: '200px'
}
],
$container = $('#example_handsontable');
$container.handsontable({
data: mydata,
minSpareRows: 0,
colHeaders: true,
columns: columnsList
});
});
function summerNoteRenderer(instance, td, row, col, prop, value, cellProperties) {
Handsontable.TextCell.renderer.apply(this, arguments);
}
// SummerNote plugin
(function (Handsontable) {
"use strict";
var SummerNoteEditor = Handsontable.editors.TextEditor.prototype.extend();
SummerNoteEditor.prototype.prepare = function (row, col, prop, td, originalValue, cellProperties) {
Handsontable.editors.TextEditor.prototype.prepare.apply(this, arguments);
};
SummerNoteEditor.prototype.createElements = function () {
this.$body = $(document.body);
this.TEXTAREA = document.createElement('input');
this.TEXTAREA.setAttribute('type', 'text');
this.$textarea = $(this.TEXTAREA);
Handsontable.Dom.addClass(this.TEXTAREA, 'handsontableInput');
this.textareaStyle = this.TEXTAREA.style;
this.textareaStyle.width = 0;
this.textareaStyle.height = 0;
this.TEXTAREA_PARENT = document.createElement('DIV');
Handsontable.Dom.addClass(this.TEXTAREA_PARENT, 'handsontableInputHolder');
this.textareaParentStyle = this.TEXTAREA_PARENT.style;
this.textareaParentStyle.top = 0;
this.textareaParentStyle.left = 0;
this.textareaParentStyle.display = 'none';
this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);
this.instance.rootElement.appendChild(this.TEXTAREA_PARENT);
var that = this;
this.instance._registerTimeout(setTimeout(function () {
that.refreshDimensions();
}, 0));
};
var onSummerNoteInit = function () {
console.log('Summmer initialized');
// this.close();
// this.finishEditing();
};
var onSummerNoteEnter = function () {
console.log('Summmer Enter');
//this.close();
//this.finishEditing();
};
var onBeforeKeyDown = function (event) {
var instance = this;
var that = instance.getActiveEditor();
var keyCodes = Handsontable.helper.keyCode;
var ctrlDown = (event.ctrlKey || event.metaKey) && !event.altKey; //catch CTRL but not right ALT (which in some systems triggers ALT+CTRL)
//Process only events that have been fired in the editor
if (!$(event.target).hasClass('summernote') || event.isImmediatePropagationStopped()) {
return;
}
if (event.keyCode === 17 || event.keyCode === 224 || event.keyCode === 91 || event.keyCode === 93) {
//when CTRL or its equivalent is pressed and cell is edited, don't prepare selectable text in textarea
event.stopImmediatePropagation();
return;
}
var target = event.target;
switch (event.keyCode) {
case keyCodes.ARROW_RIGHT:
if (Handsontable.Dom.getCaretPosition(target) !== target.value.length) {
event.stopImmediatePropagation();
} else {
that.$textarea.summernote('destroy');
}
break;
case keyCodes.ARROW_LEFT:
if (Handsontable.Dom.getCaretPosition(target) !== 0) {
event.stopImmediatePropagation();
} else {
that.$textarea.summernote('destroy');
}
break;
case keyCodes.ENTER:
var selected = that.instance.getSelected();
var isMultipleSelection = !(selected[0] === selected[2] && selected[1] === selected[3]);
if ((ctrlDown && !isMultipleSelection) || event.altKey) { //if ctrl+enter or alt+enter, add new line
if (that.isOpened()) {
that.val(that.val() + '\n');
that.focus();
} else {
that.beginEditing(that.originalValue + '\n')
}
event.stopImmediatePropagation();
}
event.preventDefault(); //don't add newline to field
break;
case keyCodes.A:
case keyCodes.X:
case keyCodes.C:
case keyCodes.V:
if (ctrlDown) {
event.stopImmediatePropagation(); //CTRL+A, CTRL+C, CTRL+V, CTRL+X should only work locally when cell is edited (not in table context)
}
break;
case keyCodes.BACKSPACE:
case keyCodes.DELETE:
case keyCodes.HOME:
case keyCodes.END:
event.stopImmediatePropagation(); //backspace, delete, home, end should only work locally when cell is edited (not in table context)
break;
}
};
SummerNoteEditor.prototype.open = function (keyboardEvent) {
this.refreshDimensions();
this.textareaParentStyle.display = 'block';
this.instance.addHook('beforeKeyDown', onBeforeKeyDown);
this.$textarea.css({
height: $(this.TD).height() + 4,
'min-width': $(this.TD).outerWidth() - 4
});
var self = this;
this.$textarea.summernote({ focus: true });
// setTimeout(function () { $('.summernote').find('.note-editable').focus(); }, 200);
};
SummerNoteEditor.prototype.init = function () {
Handsontable.editors.TextEditor.prototype.init.apply(this, arguments);
};
SummerNoteEditor.prototype.close = function () {
this.instance.listen();
this.instance.removeHook('beforeKeyDown', onBeforeKeyDown);
this.$textarea.off();
this.$textarea.hide();
Handsontable.editors.TextEditor.prototype.close.apply(this, arguments);
};
SummerNoteEditor.prototype.val = function (value) {
if (typeof value == 'undefined') {
return this.$textarea.val();
} else {
this.$textarea.val(value);
}
};
SummerNoteEditor.prototype.focus = function () {
this.instance.listen();
// DO NOT CALL THE BASE TEXTEDITOR FOCUS METHOD HERE, IT CAN MAKE THIS EDITOR BEHAVE POORLY AND HAS NO PURPOSE WITHIN THE CONTEXT OF THIS EDITOR
//Handsontable.editors.TextEditor.prototype.focus.apply(this, arguments);
};
SummerNoteEditor.prototype.beginEditing = function (initialValue) {
var onBeginEditing = this.instance.getSettings().onBeginEditing;
if (onBeginEditing && onBeginEditing() === false) {
return;
}
Handsontable.editors.TextEditor.prototype.beginEditing.apply(this, arguments);
};
SummerNoteEditor.prototype.finishEditing = function (isCancelled, ctrlDown) {
this.instance.listen();
return Handsontable.editors.TextEditor.prototype.finishEditing.apply(this, arguments);
};
Handsontable.editors.SummerNoteEditor = SummerNoteEditor;
Handsontable.editors.registerEditor('summernote', SummerNoteEditor);
})(Handsontable);
</script>
</html>