KB.component('text-editor', function (containerElement, options) {
var textarea, viewModeElement, writeModeElement, previewElement, selectionStart, selectionEnd;
this.render = function() {
writeModeElement = buildWriteMode();
viewModeElement = buildViewMode();
containerElement.appendChild(KB.dom('div')
.attr('class', 'text-editor')
.add(viewModeElement)
.add(writeModeElement)
.build());
if (options.autofocus) {
textarea.focus();
}
};
function buildViewMode() {
var toolbarElement = KB.dom('div')
.attr('class', 'text-editor-toolbar')
.for('a', [
{href: '#', html: ' ' + options.labelWrite, click: function() { toggleViewMode(); }}
])
.build();
previewElement = KB.dom('div')
.attr('class', 'text-editor-preview-area markdown')
.build();
return KB.dom('div')
.attr('class', 'text-editor-view-mode')
.add(toolbarElement)
.add(previewElement)
.hide()
.build();
}
function buildWriteMode() {
var toolbarElement = KB.dom('div')
.attr('class', 'text-editor-toolbar')
.for('a', [
{href: '#', html: ' ' + options.labelPreview, click: function() { toggleViewMode(); }},
{href: '#', html: '', click: function() { insertEnclosedTag('**'); }},
{href: '#', html: '', click: function() { insertEnclosedTag('_'); }},
{href: '#', html: '', click: function() { insertEnclosedTag('~~'); }},
{href: '#', html: '', click: function() { insertPrependTag('> '); }},
{href: '#', html: '', click: function() { insertPrependTag('* '); }},
{href: '#', html: '', click: function() { insertBlockTag('```'); }}
])
.build();
var textareaElement = KB.dom('textarea');
textareaElement.attr('name', options.name);
if (options.tabindex) {
textareaElement.attr('tabindex', options.tabindex);
}
if (options.required) {
textareaElement.attr('required', 'required');
}
// Order is important for IE11 (especially for the placeholder)
var textWrapper = KB.dom(containerElement).find('script');
textareaElement.text(textWrapper.innerText);
if (options.placeholder) {
textareaElement.attr('placeholder', options.placeholder);
}
textarea = textareaElement.build();
if (options.suggestOptions) {
KB.getComponent('suggest-menu', textarea, options.suggestOptions).render();
}
return KB.dom('div')
.attr('class', 'text-editor-write-mode')
.add(toolbarElement)
.add(textarea)
.build();
}
function toggleViewMode() {
KB.dom(previewElement).html(marked(textarea.value, {sanitize: true}));
KB.dom(viewModeElement).toggle();
KB.dom(writeModeElement).toggle();
}
function getSelectedText() {
return textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
}
function replaceTextRange(s, start, end, substitute) {
return s.substring(0, start) + substitute + s.substring(end);
}
function insertEnclosedTag(tag) {
var selectedText = getSelectedText();
insertText(tag + selectedText + tag);
setCursorBeforeClosingTag(tag);
}
function insertBlockTag(tag) {
var selectedText = getSelectedText();
insertText('\n' + tag + '\n' + selectedText + '\n' + tag);
setCursorBeforeClosingTag(tag, 2);
}
function insertPrependTag(tag) {
var selectedText = getSelectedText();
if (selectedText.indexOf('\n') === -1) {
insertText('\n' + tag + selectedText);
} else {
var lines = selectedText.split('\n');
for (var i = 0; i < lines.length; i++) {
if (lines[i].indexOf(tag) === -1) {
lines[i] = tag + lines[i];
}
}
insertText(lines.join('\n'));
}
setCursorBeforeClosingTag(tag, 1);
}
function insertText(replacedText) {
textarea.focus();
var result = false;
var selectionPosition = KB.utils.getSelectionPosition(textarea);
selectionStart = selectionPosition.selectionStart;
selectionEnd = selectionPosition.selectionEnd;
if (document.queryCommandSupported('insertText')) {
result = document.execCommand('insertText', false, replacedText);
}
if (! result) {
try {
document.execCommand('ms-beginUndoUnit');
} catch (error) {}
textarea.value = replaceTextRange(textarea.value, selectionStart, selectionEnd, replacedText);
try {
document.execCommand('ms-endUndoUnit');
} catch (error) {}
}
}
function setCursorBeforeClosingTag(tag, offset) {
offset = offset || 0;
var position = selectionEnd + tag.length + offset;
textarea.setSelectionRange(position, position);
}
});