I am looking for a very minimal jQuery rich textbox plugin for a web app I am working on.
The user will only need to see the 'textbox', and not any toolbars as all of the rich formatting will be coded depending on what they type.
I have attempted to create my own with an iframe, but there are problems. One of them being when wrapping strings in divs, the caret is moved to the beginning and it can't be moved inside the div without clicking. http://jsfiddle.net/DVjYa/
This is a problem because I need it to behave like a normal textbox. In a normal textbox, you would be able to navigate with the arrow keys without having to click. Hence why I am looking for a plugin which has already overcome these problems.
You can use CLEDITOR which is very lightweight. You can disable all the toolbar buttons and hide the toolbar as well. In addition to this, it lets you make the selection bold/italic using keyboard shortcuts (CTRL+B/CTRL+I) even though the toolbar does not exist.
Demo: http://jsfiddle.net/Rft3A/
var editorDoc;
$(function() {
var editor = document.getElementById ("editable");
if (editor.contentDocument) {
editorDoc = editor.contentDocument;
} else {
editorDoc = editor.contentWindow.document;
}
var editorBody = editorDoc.body;
if ('contentEditable' in editorBody) {
// allow contentEditable
editorBody.contentEditable = true;
}
else { // Firefox earlier than version 3
if ('designMode' in editorDoc) {
// turn on designMode
editorDoc.designMode = "on";
}
}
});
will add another answer although post is a little old
Trumbowyg A lightweight and amazing WYSIWYG JavaScript editor - 15kB only (from github page)
Related
My current Chrome extension is supposed to programmatically insert text on user input. This works great, however, it mangles the undo/redo behavior of all text editors I've tried it on so far. So, the following routine:
type some text
insert some text programmatically
type more text
press ctrl-z thrice
does not always revert to a blank state. Very often it will get stuck somewhere in the middle. Its behaviour is mostly inconsistent.
Here's an MCVE of the content script:
function init() {
var $input = document.getElementsByTagName("textarea")[0];
if (!$input) {
console.log("No input element found.");
return true;
}
var $btn = document.createElement("button");
$btn.innerHTML = "Click";
$btn.addEventListener("click", function() {
var caretPos = $input.selectionStart;
$input.value = $input.value.substring(0, caretPos) + " test string " + $input.value.substring(caretPos);
});
$input.parentElement.insertBefore($btn, $input);
return true;
}
window.addEventListener("load", init);
<div><textarea></textarea></div>
(I also bundled it as a Chrome extension in case you'd like that.)
I want the undo/redo to function perfectly in both textarea as well as contenteditable nodes. I also tried document.execCommand in both insertText and insertHTML modes without any success. I've looked at the other two related questions but they do not answer my query. (q1, q2)
What else can be a possible solution to this problem?
Thanks to the helpful comments above, my problem was doing execCommand on pre-programmed weird editors like Facebook messenger box, tinymce, etc. They might have their own customizations interfering.
In normal text editors, document.execCommand should work fine, and support undo/redo. Use it like so:
document.execCommand('insertText', false, "text");
document.execCommand('insertHTML', false, "html");
I've been trying out the excellent Medium Editor. The problem that I've been having is that I can't seem to get links to "work".
At the simplest, here's some HTML/JS to use to demonstrate the problem:
HTML:
<html>
<head>
<script src="//cdn.jsdelivr.net/medium-editor/latest/js/medium-editor.min.js"></script>
<link rel="stylesheet" href="//cdn.jsdelivr.net/medium-editor/latest/css/medium-editor.min.css" type="text/css" media="screen" charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/medium-editor/latest/css/themes/beagle.min.css" type="text/css">
</head>
<body>
<div class='editable'>
Hello world. link
</div>
</body>
</html>
Javascript:
var editor = new MediumEditor('.editable');
This fiddle demonstrates the problem (using the code above).
If you hover on the link, a popup appears.
If you click the link, nothing happens.
If you click the popup, a form appears where you can edit the link.
It seems to me that clicking the link should take me wherever the link's href is targeting. The only way to use the link is to right click and either open in a new tab or new window -- which I don't want to ask my users to do.
I feel like I must be missing something simple in the configuration (either the Anchor Preview Options or the Anchor Form Options). Unfortunately, I'm not seeing it.
In my actual application, I'm not using jQuery, but I am using angularjs. If a strictly Medium Editor answer doesn't exist, I can fall back to using basic JS or anything that angularjs provides.
I've found how to bind event.
Here is full event list https://github.com/yabwe/medium-editor/blob/master/CUSTOM-EVENTS.md
Try to change your code to
var editor = new MediumEditor('.editable')
.subscribe("editableClick", function(e){if (e.target.href) {window.open(e.target.href)}})
https://jsfiddle.net/fhr18gm1/
So medium-editor is built on top of the built-in browser support for contenteditable elements. When you instantiate medium-editor, it will add the contenteditable=true attribute to whatever element(s) you provided it.
By default, since the text is now editable (the contenteditable attribute makes the browser treat it as WYSIWYG text) the browser no longer supports clicking on the links to navigate. So, medium-editor is not blocking these link clicks from happening, the browsers do it inherently as part of making the text editable.
medium-editor has built in extensions for interacting with links:
anchor extension
allows for adding/removing links
anchor-preview extension
shows a tooltip when hovering a link
when the tooltip is clicked, allows for editing the href of the link via the anchor extension
I think the underlying goal of the editor is the misunderstanding here. The editor allows for editing text, and in order to add/remove/update links, you need to be able to click into it without automatically navigating away. This is what I think of as 'edit' mode.
However, the html produced as a result of editing is valid html, and if you take that html and put it inside an element that does NOT have the contenteditable=true attribute, everything will work as expected. I think of this as 'publish mode'
I look at editors like word or google docs, and you see a similar kind of behavior where when you edit the document, the links don't just navigate away when you click on them, you have to actually choose to navigate them through a separate action after you click the link. However, on a 'published' version of the document, clicking the link will actually open a browser window and navigate there.
I think this does make for a good suggestion as an enhancement to the existing anchor-preview extension. Perhaps the tooltip that appears when hovering a link could have multiple options in it (ie Edit Link | Remove Link | Navigate to URL).
tldr;
Links are not navigable on click when 'editing' text in a browser via the built-in WYSIWYG support (contenteditable). When not in 'edit' mode, the links will work as expected.
This could make for a nice enhancement to the medium-editor anchor-preview extension.
Working off some ideas from #Valijon in the comments, I was able to get it to work using the following code:
var iElement = angular.element(mediumEditorElement);
iElement.on('click', function(event) {
if (
event.target && event.target.tagName == 'A' &&
event.target.href && !event.defaultPrevented) {
$window.open(event.target.href, '_blank');
}
});
I think the key is that apparently the editor lets the event propogate to the ancestor elements, so I was able to just listen for the click on the top level editor element.
Here, $window is angular's $window service -- If you're not using angularjs, window would do the trick and I used angular.element to ease the event listener registry, but you could do it the old-fashioned way (or using the JS framework of your choice).
What I really wanted when I asked the question was behavior similar to Google Docs when in "edit" mode (as described by Nate Mielnik). I opened an issue on the Medium Editor tracker and they decided not to implement it as part of the core medium editor, but they noted that they would be happy to have someone add that functionality as an extension.
So, I decided to implement that functionality as an extension as suggested. It can be found as part of MediumTools1. The project is still in very early stages (e.g. I haven't done anything to make the styling look better, or to use better minifying practices, etc. but we'll happily accept Pull Requests for that).
The guts of the code look like this:
var ClassName = {
INNER: 'medium-editor-toolbar-anchor-preview-inner',
INNER_CHANGE: 'medium-editor-toolbar-anchor-preview-inner-change',
INNER_REMOVE: 'medium-editor-toolbar-anchor-preview-inner-remove'
}
var AnchorPreview = MediumEditor.extensions.anchorPreview;
GdocMediumAnchorPreview = MediumEditor.Extension.extend.call(
AnchorPreview, {
/** #override */
getTemplate: function () {
return '<div class="medium-editor-toolbar-anchor-preview">' +
' <a class="' + ClassName.INNER + '"></a>' +
' -' +
' <a class="' + ClassName.INNER_CHANGE + '">Change</a>' +
' |' +
' <a class="' + ClassName.INNER_REMOVE + '">Remove</a>' +
'</div>';
},
/** #override */
createPreview: function () {
var el = this.document.createElement('div');
el.id = 'medium-editor-anchor-preview-' + this.getEditorId();
el.className = 'medium-editor-anchor-preview';
el.innerHTML = this.getTemplate();
var targetBlank =
this.getEditorOption('targetBlank') ||
this.getEditorOption('gdocAnchorTargetBlank');
if (targetBlank) {
el.querySelector('.' + ClassName.INNER).target = '_blank';
}
var changeEl = el.querySelector('.' + ClassName.INNER_CHANGE);
this.on(changeEl, 'click', this.handleClick.bind(this));
var unlinkEl = el.querySelector('.' + ClassName.INNER_REMOVE);
this.on(unlinkEl, 'click', this.handleUnlink.bind(this));
return el;
},
/** Unlink the currently active anchor. */
handleUnlink: function() {
var activeAnchor = this.activeAnchor;
if (activeAnchor) {
this.activeAnchor.outerHTML = this.activeAnchor.innerHTML;
this.hidePreview();
}
}
});
As an explanation, I just use medium's flavor of prototypical inheritance to "subclass" the original/builtin AnchorPreview extension. I override the getTemplate method to add the additional links into the markup. Then I borrowed a lot from the base implementation of getPreview, but I bound new actions to each of the links as appropriate. Finally, I needed to have an action for "unlinking" the link when "Remove" is clicked, so I added a method for that. The unlink method could probably be done a little better using contenteditable magic (to make sure that it is part of the browser's undo stack), but I didn't spend the time to figure that out (though it would make a good Pull Request for anyone interested :-).
1Currently, it's the only part, but I hope that'll change at some point. . .
When using tinyMCE in a jqueryUI modal dialog, I can't use the hyperlink or 'insert image' features.
Basically, after lots of searching, I've found this:
http://www.tinymce.com/develop/bugtracker_view.php?id=5917
The weird thing is that to me it seams less of a tinyMCE issue and more of a jqueryUI issue since the problem is not present when jqueryUI's modal property is set to false.
With a richer form I saw that what happens is that whenever the tinyMCE loses focus, the first element in the form gets focus even if it's not the one focused / clicked.
Does some JavaScript guru have any idea how I might be able to keep the dialog modal and make tinyMCE work?
This fixed it for me when overriding _allowInteraction would not:
$(document).on('focusin', function(e) {
if ($(event.target).closest(".mce-window").length) {
e.stopImmediatePropagation();
}
});
I can't really take credit for it. I got it from this thread on the TinyMCE forums.
(They have moved their bugtracker to github. tinymce/issues/703 is the corresponding github issue.)
It seems there are no propper solution for this issue yet. This is kind of a hack but it really worked for me.
Every time you open the Dialog remove the text area and re add it like following,
var myDialog = $('#myDialog');
var myTextarea = myDialog.find('textarea');
var clonedTextArea = myTextarea.clone(); // create a copy before deleting from the DOM
var myTextAreaParent = myTextarea.parent(); // get the parent to add the created copy later
myTextarea.remove(); // remove the textarea
myDialog.find('.mce-container').remove(); // remove existing mce control if exists
myTextAreaParent.append(clonedTextArea); // re-add the copy
myDialog.dialog({
open: function(e1,e2){
setTimeout(function () {
// Add your tinymce creation code here
},50);
}
});
myDialog.dialog('open');
This seems to fix it for me, or at least work around it (put it somewhere in your $(document).ready()):
$.widget('ui.dialog', $.ui.dialog, {
_allowInteraction: function(event) {
return ($('.mce-panel:visible').length > 0);
}
});
In IOS5 on the iPad, iPad2 etc. iBooks accepted <input type="color"> as a way to prompt the keyboard to display when you clicked on an input field, to say, type in the answer to a question. I've just recently updated to IOS6, and this workaround no longer seems to be working. I tried using the JavaScript I found here - http://www.linkedin.com/groups/How-Show-iPads-Keyboard-when-3877009.S.84287009
<script type="text/javascript">
function iPadTouchHandler(event) {
var type = "",
button = 0; /*left*/
if (event.touches.length > 1)
return;
switch (event.type) {
case "touchstart":
// OLD: On iPad2 clicking on a text input field did not show the keyboard
// if ($(event.changedTouches[0].target).is("select")) {
// NEW: Now on iPad2 the touchstart-Event on input fields is ignored and everything works fine
// change my by Roland Caspers, Scheer Management
if ($(event.changedTouches[0].target).is("select") || $(event.changedTouches[0].target).is("input")) {
return;
}
iPadTouchStart(event); /*We need to trigger two events here to support one touch drag and drop*/
event.preventDefault();
return false;
break;
</script>
However this code seems to be outdated and relevant to IOS5. I know of a workaround, which is to put the page with the input into an iFrame, in that case you can just use <input type="text">, however I'd prefer to stay away from iFrames as they tend to move the content around depending on where the input box is. Any thoughts as to other possible solutions or workarounds? Tyvm :)
I am also Facing the same issue on iOS6 for , the same is working perfectly on the <iframe> tag. But it omits the images & style and etc.
Review the code "http://www.linkedin.com/groups/How-Show-iPads-Keyboard-when-3877009.S.84287009", I feel some thing has to modify on below condition:
($(event.changedTouches[0].target).is("select") || $(event.changedTouches[0].target).is("input"))
I'd be great if anyone provide the earlier response.
Thanks
I struggled with this same problem in iBooks on iOS 7. The tricky part was, that iBooks probably makes all text input fields disabled by default. We are using prototype.js, so here is my solution written for prototype:
$('my-input-field-id').observe('touchstart', function(event) {
var element = event.element();
if (element.disabled)
element.disabled = false;
element.focus();
event.stop();
});
So just listen for the 'touchstart' event on the input field and enable and focus the field when touched. It works for ordinary text fields (<input type="text">). Simple :-).
I was wondering if anybody knows how I would go about detecting when the scrollbar appears inside a textarea.
I am currently using mootools for my JavaScript and I am having issues getting it to detect a scrollbar.
function has_scrollbar(elem_id)
{
const elem = document.getElementById(elem_id);
if (elem.clientHeight < elem.scrollHeight)
alert("The element has a vertical scrollbar!");
else
alert("The element doesn't have a vertical scrollbar.");
}
See this jsFiddle http://jsfiddle.net/qKNXH/
I made a jQuery "compatible" version of Tommaso Taruffis code
function resize_until_scrollbar_is_gone(selector) {
$.each($(selector), function(i, elem) {
while (elem.clientHeight < elem.scrollHeight) {
$(elem).height($(elem).height()+5);
}
});
}
It can handle multiple elements and accepts: selectors, jQuery objects, or DOM elements.
It can be called like this:
resize_until_scrollbar_is_gone('textarea');
Tommaso's solution works perfectly, even with a text area. But if the user were to type in the textarea and suddenly the textarea gave itself a scrollbar, your javascript wouldn't know or be triggered.So you might want to add something like
onKeyUp='has_scrollbar("textareaID")'
For React I've found https://github.com/andreypopp/react-textarea-autosize
import Textarea from 'react-textarea-autosize';
...
<Textarea maxRows={3} />