I want to create a Form Input in a Web Page and have Custom Text Formatting Options like Bold, Italic and Adding HyperLink.
Pretty much similar to how asking a question in StackOverflow.
The primary purpose is to get the html output of what user enters in the form. For example, if user selects Bold Button and types something, i should get that part as
<b>Bold Content</b>
Need suggestions on how to achieve this.
Thanks
There are various ways to approach this, I'm going to tackle 2 fairly simple ones
The first thing to note is that you want to wrap your editor in a container element with the contenteditable attribute, then have an array variable, containing text strings and "events" of styling strings, encoded in whichever way you prefer (maybe strings starting with :, like ":bold").
What you don't want to do is directly store the html, but rather the states that can then be translated into html code.
Whenever the user writes, you'd capture the keystrokes (and prevent them from default behaviour) to add to the last text string (or add a new one in case the last was an event), and if the keystroke is, say, a backspace, then if the last item is an event, you remove all events on the tail of the array ( so [ "this ", ":bold", "is ", ":no-bold", ":italic", "text", ":no-italic", ":bold" ], which you'd later turn to "this is text ", would turn into [ "this", ":bold", "is", ":no-bold", ":italic", "tex" ])
Now you can do 2 major things.
Firstly, you can add a span for each text character, and assign the various classes based on the event styles so that each character has its own element:
<span class="">t</span><span class="">h</span>...<span class="bold">i</span><span class="bold">s</span><span class="bold"> </span><span class="italic">t</span>...
This is very slow for the browser to render, but will work quite well.
The other thing you can do, is evolving the previous example by working on each text string rather than each character, so you'd start a span for every transition from text to event in the array, assuming you're iterating over it, and add classes corresponding to the various types until you get a transition from event to text, in which case you insert the text, and close it before another event occurs, and simply repeat:
<span class="">this </span><span class="bold">is </span><span class="italic">text</span>
Much more concise and quite easy to get to. Alternatively you can add a <b> tag for every :bold event, a </b> for every :no-bold and similar. This is however highly discouraged. If you're missing it: in css you can have font-weight to describe boldness and other properties for italic and other styles
TinyMCE gives you all these features (and more) straight out of the box.
Related
I want to have an input field that formats the text that get put into it dynamically. For example I want that every word that begins with an hashtag get turned in bold text. More precisely if I write #todolist some task than this text should instantly look like this #todolist some task
Initially I tried the <input> and the <textarea> elements, but that dit not work at all. I figured out that there is an attribute called contenteditable which allows to edit text inside a <div>. But I wonder if there is a better solution instead of using a <div> element?
Unfortunately, general <input>, <textarea>, <select> and all the other default editable elements are not able to have any other child elements, thus, you can not do the text bold (<b>) or italic (<em>).
The best solution is a <div> with contenteditable attribute.
The article more on the contenteditable:
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content
The value of input or textarea is DOMString.
Value: A DOMString representing the text contained in the text field. MDN
and you can not style (e.g. set font-weight) two-parted text without wrapping it in a DOM element.
Here is another idea which is also feasible:
You can set two input elements side by side, hide all of the native input stylesheet traces, and listen for onChagne values if it starts with # or anything more specific, you can change the style of the first input to bold or any other thing. Then blur the first input and focus on the second input.
there are lots of concerns you should take responsibility for now:
cross-browser UI compatibility for your inputs.
handle UI edge cases for the value that doesn't start with # (maybe setting the width of next input to 0 then).
60 fps animation rate (or UI decomposition) for blur/focus effect.
keyboard will face a flash of close-open in this switching (blur/focus).
When an insertReplacementText input event type, as defined in this W3C Editor's Draft, takes place on a textarea element, the data property or attribute provides the text that was added to the textarea value, replacing some other text, such as when right-click on a misspelled word and the context menu provides suggested words.
The misspelled word does not have to be selected first; and, if the textarea has the focus (the cursor could be far from the misspelled word), when the right click takes place, the cursor is not moved at all.
After the replacement, the cursor is positioned to the right of the new text, as in a paste event. The difficulty is determining the length of the text that was replaced and or it's value.
I ask because I'd like to capture the needed information to undo/redo this event.
Thank you.
Update:
If you maintain a copy of the last value of the textarea in RAM or other lcoal storage options, then there is a way to accomplish this; although the event itself provides little data. I was rather stupid at first, as I was testing this in a separate piece of code, because I forgot that, in the code of my particular project, there is always in RAM a copy of the last value in the textarea. Having that information makes this operation very similar to a paste event when there is a selection before the paste that is replaced by the pasted text. After the replacement is performed, the cursor is positioned immediately to the right of the last character of the replacement text. The data property of the insertReplacementText event contains the value of the inserted text.
Thus, it is a matter of arithmetic involving the length of the new text, the difference in the length of the previous copy of the textarea value's length and the length of the DOM element's value after replacement, and the cursor position after the replacement has been performed. The difference in the length's of the textarea values is the difference in the length of the old text and new text. This provides the selection range from which to extract the old text from the saved copy before updating the copy to the new value. The selectionStart is the same for both the old text and new text; the difference is in the selectionEnd based on the lengths, if not equal.
As long as the browser keeps positioning the cursor to the right of the last character of the replacement text, and you maintain a copy of the last value of the textarea, it appears that this ought to work.
Thank you.
I want to make a text editor. It should work the way all text editors work (including this one i am using right now), so the user makes a selection of the text, presses a button or whatever, and then some function is executed.
I want my editor to work in the following way:
1. User selects
2. Function selected() is triggered that makes a span around the selected text.
3. When user clicks a button such as "B" or "I", they invoke functions that change .style of the span element.
For now I figured out how to get string from user selection, nothing more than that.
<body>
<textarea onselect="selected()">Some text here, more text here.</textarea>
</body>
<script>
function selected() {
var preselection = window.getSelection();
selection = preselection.toString();
console.log(selection);
}
</script>
textareas can't contain spans, so you will need to use something like this if you decide to use spans:
<p contenteditable="true" ...
You probably don't want to fire your function every time a user makes a selection. Instead, just run the function if a user presses a button (like the bold button) and then pick up the selected text, if any, using something like:
document.getSelection().toString()
Now adding a <span> object to an HTML element is pretty easy, but the big challenge here is that you don't know if your selection will cross other span objects (like if the user already added some formatting). Notice that stackoverflow inserts characters like ** in the edit area and then does one pass to add in tags like <strong>. This is possible in a text area as well, so you wouldn't need contenteditable="true".
It is possible to analyze what is in your selection and then collect all elements involved, and rewrite them as needed. You would have to get all parent objects involved in the selection and then add <span> elements around the text inside each of the parent objects.
To simplify this, you might make a rule that only one level of tags is allowed in your editable region, and then always re-write for that so that the results would only have one level of span:
<span class="bold">This whole sentence is italic and </span><span class="italic_bold">this half is also bold.</span> with no nesting of these span tags.
Investigating these properties might help with dealing with nesting: https://developer.mozilla.org/en-US/docs/Web/API/Selection
These string commands might also help:
https://www.w3schools.com/jsref/jsref_obj_string.asp
I have a textarea #myarea into which I'm typing text. I've typed this text.
This is a sentence and only this word
will end up being bolded
Now I have a button on the side, like a bold button. I want to select the letters I want bolded, click the button, and see those letters turn bold inside the textarea. It's similar to the standard functionality found in many editors, but I'm looking for something much simpler as I described here.
So is there a way to do this with jquery? I'm guessing it's a 2-part problem. I need to find the letters selected, then apply bold to them so it shows bold inside the textarea.
If you don't mind using a div that has its ContentEditable property set to true then you can easily do this using:
document.execCommand('bold',null,false);
You can easily style this div to look and feel like a textarea.
See jsFiddle here: http://jsfiddle.net/hqvDT/1/
Note: I have a workaround to this problem, but I'd prefer to comma-separate the values as I describe below rather than separating them with spaces (which is what my workaround does).
I have an ASP.NET website that allows instructors to choose from a DropDownList of preset comments and apply these comments to students in their classes. I display the students and comments inside a GridView, and use a Label to display any comments that already exist in the database (removing them from the DropDownList in the process). When an instructor selects one of these comments and clicks a button, my jQuery function:
Pulls the selected value and text out of the option (provided it isn't the default option).
Checks Label.children().length, and appends a ", " to the text if it's greater than zero.
Creates a <span> tag with a hidden field containing the value and text.
Appends the text inside the span.
Closes the span.
Attaches an onclick event to the span.
Removes the original option from the DropDownList.
The span tag's onclick event does the reverse of what I describe above -- it pulls the value and text out and re-creates the option inside the drop-down menu. Additionally, it replaces strings like ", , " with ", " in the parent Label. I've found that when I replace these strings (which lie outside the spans I've attached the onclick events to) that the onclick events go away.
I'm familiar with .live(), but because each row in this GridView contains a unique reference to the particular student and class currently in use, I can't know the values that each row needs to pass into the funciton ahead of time. Is there any solution to this problem other than my described workaround or re-attaching the onclick event?
Here's an idea: Wrap the commas in <span>s with some class like 'separator'. Then, when you remove an item, you can check to see if it's the first thing in the list, and if so, remove the subsequent seperator, and if not, remove the previous one. So we'll say you have an html structure like so:
<span id="myLabel">
<span class="comment">You're great!</span><span class="separator">, </span><span class="comment">You're mediocre!</span><span class="separator">, </span><span class="comment">You suck!</span>
</span>
Here's a click function that should remove the commas properly, while maintaining the onclick events:
$('.comment').click(function() {
//decide which comma to remove
if ($(this).prevAll('.comment').size() == 0) {
//this is the first comment, remove the next comma and this comment
$(this).next('.separator').remove().end().remove();
} else {
//this is not the first comment, remove the previous comma and this comment
$(this).prev('.separator').remove().end().remove();
}
});
Here's a live demo showing that this works: http://jsfiddle.net/yWet5/
Sorry if I've misunderstood any part of your problem.