Problems with custom divs within WYSIWYG, cross-browser - javascript

I am working on a WYSIWYG editor (customising someone else's code) and have encountered a few problems that I just can't seem to overcome.
So far I have been able to get most custom divs working, but I am having some trouble with a few things:
Problem 1: If the cursor is before a div element, I am able to press delete and begin to remove the contents of the div without removing the actual div itself. This is how the element should look within the WYSIWYG for example:
But after pressing delete when the cursor is before the element, I get the following:
How can I check if the next element is this custom div and cancel a delete key press?
Problem 2: I am also able to press backspace after an element, which causes any text after the element to appear inside it, like so:
How can I check if the previous element is my custom div and cancel a backspace key press?
Problem 3: When inside a section (where the 'put content here' text is), I am using a div with the attribute contenteditable="true". Every time I press 'enter' within this div, a new <div> tag is created, rather than a line break tag (<br>). How can I force a line break tag to be created instead of a div element?
I have looked far and wide on stackoverflow and have yet to find a proper solution to the problem that is cross-browser.

Disclaimer: I am a CKEditor core developer.
If you want to customise this there are three ways:
You can spend few months (or more) on learning about contenteditable, ranges, selection and all that stuff and trying to implement your custom handlers. You could of course spend only one week or month on that, but the result won't be great, believe me.
You can choose good, existing WYSIWYG editor.
You can lower your expectations regarding the expected behaviour ;).
Now, if you would decide to use CKEditor there's one new feature called Widgets which was introduced in recently released CKEditor 4.3 beta (4.3 stable is going to be released in max. 2-3 weeks). As far as I can see it may be very helpful in your case. Check out the Introduction to Widgets guide. In very short - it is possible to configure how enter key behaves in so called "nested editables" as well as to secure integrity of your custom markup.

Related

Change CKeditor direction dynamically

I've check numerous questions on SO but couldn't achieve required behaviour.
I have registered an on change listener on ckeditor instance, when a charecter is typed I check if the language is persian or not.
If the language is persian, direction should be changed to RTL automatically.
Similiar question has been asked here but reinitializing the editor doesn't create a nice ux.
Another approach I tried was to change config of the editor on the fly, but apparently Ckeditor ignores it completely.
the way I did was:
CKEDITOR.replace('editor1', newConfig);
So my question is: how do I change ckeditor's direction on the fly without reinitializing the instance?
You could take a look at BiDi plugin which allows to change text direction of any block-level element (e.g. paragraphs) - see this SDK sample.
So if on change event you detect that Persian was typed, you may automatically update the block-level element dir attribute (that's what BiDi plugin is using). To get block-level element based on current selection take a look at elementPath and its block property.

Rangy for subdivided contenteditable div

So, I'm playing around with the (AWESOME) Rangy text selection package. I'm editing text inside of a span with contenteditable=true, with the goal of having a text input element which allows individual styling of each character. Let me stress that last point -- each character should be in its own span. This works fine if I don't need to preserve the styling from one keystroke to the next -- I just do something like
var newHTML = field.innerText.split('').map(function(c){
return ('<span class="letter">'+c+'</span>');
}).join('');
$(field).empty().append(newHTML);
and use Rangy's (1.3) saveCharacterRange() function to restore the selection, and it's all good.
The problem comes when I've already styled some of those spans, and I delete one, replacing it with new text. I want newly inserted text to be unstyled, but instead it gets inserted into the preceding (or following, if the selection is at the beginning) span. I've tried to work around this by explicitly collapsing the selection's region after (or before) the focusNode, but it seems to not allow the endContainer (or startContainer) to be anything other than a text node... I've even verified that I can create a text range which collapses where I want it, but the selection object's setSingleRange() seems to collapse back around the text node.
I tried inserting a new node and placing the selection wholly inside it, which does work when the new node has content in it before calling insertNode(), but I obviously can't be inserting extra content between each character...
Here's a fiddle demonstrating what I'm talking about. Thanks for any help!
I think you're falling foul of a common issue: browsers (particularly WebKit) have specific ideas of where in the document the selection and caret are allowed to be. Here's a recent answer of mine on this subject:
https://stackoverflow.com/a/21591165/96100
Maybe somebody out there can expand on this, but I think save/restoreCharacterRanges() is the key to fixing this problem. I've got it working (assuming your selection region is collapsed) in this fiddle, though not the way I'd like -- this approach (removing the just added content and moving into a new span) causes a flicker between keyup and keydown. I'd really like to be able to move the cursor (on keydown) into a fresh span, which would appear seamless to the user...
... and here's a fiddle that works with long selections, but not pasting...
Update
I've switched over to the 'insert a <span>὘</span> and move the selection region into it' approach, which seemed to be working great, until I started trying different browsers. The behavior is completely different in each browser! Chrome correctly moves the cursor into a 'blank' span when required, but then removes the accent; Firefox handles accented characters perfectly, but fails to move into the new span after deleting a character which follows a new span; Safari displays the accent mark then moves into the new span, leaving the accent mark orphaned... And all three will display the original bug when deleting an old letter which follows a new one! Also, it seems like the different browsers are reporting different keycodes when modifier keys are pressed. Is this a lost cause? Am I missing something? Here's a fiddle with the new code.

Mentioning system that mimics Facebook's

I've had a horrible problem that I've been wracking my brain for the past two days for, and have yet to come up with a solution. As such, I think this needs someone smarter than I to accomplish.
What I'm trying to build is a textbox that simulates that of Facebook's; essentially, the tagging function.
Now if you've used Facebook, you'll have noticed that Facebook allows you to tag people in a comment/post, simply by typing in their name and selecting from a dropdown list. The name of the person you've selected then appears in highlighted text in that very textarea. I've successfully managed to create and populate the dropdown list a combination of JQuery and AJAX, but the tagging process itself is the stumper.
Once a dropdown item has been selected (by Enter or clicking), the query text will be replaced with the tagged name. Now, it's difficult to see how one can give text in a textarea any kind of a highlight, so I've discovered (by inspecting elements in Google Chrome and deleting the textarea node) that the textarea itself is transparent, and there is a white div below "simulating" the text. Highlighted words are placed in a tag with custom CSS, which gives it that blue background. All of this I've found out myself, and I have successfully simulated this - but I can only do one tag.
Now I've investigated further and found an input type="hidden" element, of class "mentionsHidden". This input element has a value attribute, which dynamically populates itself based on the content of the textarea. So if I typed "ABC", the value of the element becomes "ABC". If I included a tag, say "hi [Rei]!" (where the name in [] is the tag), the value of the element becomes "hi #[member_id:Rei]!".
So I HAVE done my homework. But here comes the part I can't figure out.
I can't figure out how exactly to dynamically populate the hidden input element with the value of the textbox. It's obvious that the underlying div giving the blue tag background is populated from the input element. But the input element is giving me a headache.
You see, I can't do the following:
-I can't simply "copy" the entire value of the current textarea and "paste" it into the input element's value, because that would override any previously tagged people in the input element (after all, the textarea can only possess plaintext).
-Even though I CAN locate the current index of the caret (the flashing black line in the textarea that tells you where you're going to be typing into), that's only for the textarea. Index position 10 in the textarea and in the input element's value might be different things, because this way of "tagging" people will result in adding additional characters to the value String.
-I can't simply do a "replace" of the text I am intending to replace, because there might be other instances of that same text in other parts of the value String.
I know it's a very long and confusing post, but I do hope you get what I mean. I really need a solution and I don't want to use contenteditable, because it's only for HTML5 and some older browsers might not support it.
Yours,
Rei
I hope you were able to come up with, or find, a solution to your problem. Since there doesn't seem to be one here, i'd like to offer one for and anyone who might stumble upon this (as well as you if my assumption was incorrect).
You are going to need to maintain explicit locational data of each existing mention in the textarea in the order in which they appear. If, after a modification of the content in textarea, the position of a mention in it is changed, you will need to determine which appearance of its value, if any, will be used to represent it, and appropriately update the locational data of the mention.
With such a collection of data, it becomes trivial to construct the value of mentionsHidden, though the existence of such data makes the element unnecessary.
Mentionator is an existing, robust solution which takes this approach in providing the functionality you are trying to recreate. Considering it is well-structured, easy to follow, and copiously commented, it should be of use to you as either out-of-the box solution or reference material to cite as you roll out your own. It is maintained by yours truly :) .

TinyMCE contained element?

I wrote a TinyMCE plugin for Wordpress that drops a prepared bit of HTML into the textarea when a button on the toolbar is clicked. This is to assist in formatting some relatively complicated elements.
I would like for this piece of HTML to be wrapped in some sort of container that TinyMCE recognizes and allows for easy selection or deletion if needed.
Currently, the only way to delete an individual element is by erasing all of the information each individual "sub element" contains. I can't seem to find any information in the API regarding manually assigning an element as a singular combined object. As far as behavior goes, think "resize frame" or something similar (only this won't need to have any resizing capabilities).
Any ideas?
If you want to wrap text/html inside an element of your choice (i used a span here) at the current cursor position of tinymce editor instance ed you can simply do
ed.execCommand('insertHTML', false, '<span class="custom_to_delete">My_Text</span>');

Searching for the Ultimate Resizing Textarea

I'm wanting to provide a resizing textarea control for users. I've given this a go and looked at a number of other implementations, but I can't seem to find one that meets all my requirements. Specifically I want a control that:
Works in IE6, IE7, IE8 on Windows and Firefox 3 and 3.5 on Windows and OS X when the page is rendered in standards compliant mode (i.e. not in quirks mode).
Does not mess up the undo buffer/undo stack. This is a particularly nasty issue with IE - adding nodes, removing nodes and some other DOM operations will reset the input buffer meaning that if an implementation relies on these techniques an undo will not behave like it does in a standard textarea control. I haven't been able to find much information about this bug except for this note. Implementations like the jQuery Auto Growing Plugin suffer from this problem - try undoing changes in IE and compare how this works to a standard textarea. I've added an example page demonstrating this problem to JSBin.
Has a maximum height beyond which the control cannot grow.
Shrinks appropriately when content is deleted.
Does not flicker or act strangely on keypress. e.g. jQuery Auto Growing Textarea control behaves strangely with, at least IE7, when the control has grown beyond it's initial size.
Does not require the control to use a fixed-width/monospace font.
The closest I've seen to something that works like this is Facebook's status update field, which is implemented as a content editable div element, but I have some reservations about using such an element because using a div means:
Need to explicitly style the border which means we could end up with a border that looks different to a native textarea.
Need to sync content with the real textarea (possibly in both directions?).
Adds complexity when placing hints and other elements relative to position of a textarea.
While this approach works for something like a Facebook status update, how well would it work in a form containing hundreds of standard input elements?
What I've set out above represents the "ultimate resizing textarea" - addressing what I perceive to be issues with existing approaches. Does such a control exist? Is it possible to write such a control?
Check out DOJO tools text area control
see more on this demo page (text area At the end of the form )
This closely come to your requirements.
You may need to roll your own to meet those requirements.
These could be a start.
http://tuckey.org/textareasizer/ (though try and avoid eval() in yours)
http://www.felgall.com/jstip45.htm
http://viralpatel.net/blogs/2009/06/textarea-resize-javascript-jquery-plugin-resize-textarea-html.html
This actually seems like a good jQuery plugin. I might have a tackle at developing something like this. If I get it done, I'll post it here.
I spent a few hours developing something, but then I found this one that seems to be really good.
http://www.aclevercookie.com/demos/autogrow_textarea.html
You want to auto-size the display? but leave the content the same?
That is all the scripts can do, adjust the display, and let you see more of your own text...
This A List Apart post contains an implementation that looks pretty close to meeting your criteria and contains a good explanation of what's going on.
Are any of these useful?
Textarea Resize JavaScript: Resize textarea using jQuery plugin
Smart Area: A Lightweight Resizing Text Area Plugin for jQuery
How to Build an Auto-Expanding Textarea jQuery Plugin, Part 1
How to Build an Auto-Expanding Textarea jQuery Plugin, Part 2
How to Build an Auto-Expanding Textarea jQuery Plugin, Part 3
Resizable Body
I have been using nicEdit. It seems to have all that you need and the script is only 1700 lines with an MIT license so you could make any changes you need.

Categories

Resources