How to make a span from user selection (js) - javascript

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

Related

Vanilla JavaScript toggle element with text to editable element on edit button click

I'm trying to make my first vanilla JavaScript app which is (surprisingly :D) To-Do App
I'm currently stuck with the update todo part,
I got this part of code doing to-do creation
let createTodo = (todo) => {
let span = document.createElement('span');
span.classList.add('text');
spanParent.prepend(span);
span.innerHTML += `${todo.text}`;
let edit = document.createElement('span');
edit.classList.add('edit');
spanParent.append(edit);
edit.addEventListener('click', (e) => {
console.log(e);
});
let editIcon = document.createElement('i');
editIcon.classList.add('fa-solid');
editIcon.classList.add('fa-pen-to-square');
edit.prepend(editIcon);
};
I want that when user click edit the todo text turn to editable input and save new value on enter or clicking outside and it become not editable again until pressing edit
I did some research and come across (contentEditable) attribute , but when tried to apply it things went sideways,
when i turn it on the edit icon disappear and the text stay editable
i think i need to do some kind of form that show on edit but don't know how to approach this idea
EDIT
I'll try to explain more clearly hopefully,
I need to make the to-do text to be:
1- editable when user click the edit button
2- save the new user input text
3- become non-editable once user save updates
4- become editable again if user press edit button again
Thanks in advance
Based on the description that you provided, there is technically no need of using a form. You could stick to a standalone button and give it a click handler.
The click handler of this EDIT button works as follows: it sets the contenteditable attribute on the to-do text element (the span element above). This makes the text editable.
Then when the SAVE button is pressed, you should do the following: get the textContent of the span element, store it locally (I guess you're using localStorage) and then finally remove the contenteditable attribute from the span element.
BTW, I feel that there is a lot of room of improvement in your code, for e.g. in variable naming, in the usage of methods, and in the order of statements:
append() and prepend() is, more or less, meant for bulk-insertion of nodes into the DOM. In your case, you have just one single node to add and so you could just stick to using insertBefore() or `appendChild().
Most probably, the to-do text is styled as a block in your application. Hence, it's better to make it a <div> element, instead of a <span>.
There is an awesome resource to learn about the HTML DOM, along with exercises to practice your skills: HTML DOM Introduction — CodeGuage.

How can I make word blocks of text that go inside of <textarea>s?

In the website I am working on, I need there to be a <textarea> where the user can write a description, and add user-defined variables as shown below:
When one of the buttons is clicked, it adds the corresponding text to the <textarea> above. Then, in the JS, I use the replaceAll() method to substitute the variables added with their corresponding values.
This works and all, but I would want to do is go for something that looks like this:
So I still want the block of text to function the same as before, but it would be sort of like one character, where if you hit the backspace on it it would delete the whole block. Is there a way I can go about doing this (using Vanilla JS)?
Thanks in advance!
You can't render HTML in a textarea. What you'll need is a content editable DIV – here is some rough HTML & CSS.
<div contenteditable="true" >
Hi, My Name Is BusinessName
</div>

Create Form Input with Text Formatting Options giving HTML OUTPUT

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.

Boldening text "Inside" a textarea

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/

jQuery trim and remove on parent break child events

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.

Categories

Resources