Cannot insert text into a message field on messenger.com - javascript

This is not one of those "how to insert text in input" questions. I've checked them all.
So I need to insert some text on page load into the message field on message.com.
The problem is that while the input is empty, it is just a <br data-text="true"> element. Then if you type something in, it changes to <span data-text="true"></span>. React does that.
I can add text to this span's innerHTML or textContent but in order for the tag to appear, I still need to type one letter manually into the message field. If i try to change innerHtml or textContent on br element nothing happens.
I tried selection and range:
let selection = window.getSelection();
let range = selection.getRangeAt(0);
let node = document.createTextNode(text)
range.insertNode(node);`
it kinda works, in a way that I just insert a new textnode, but I cannot send that text, so it is useless.
I spent all day on this and now I'm not even sure if it is possible.

OK, so for everyone who stumbles upon something similar, when you just can't change the DOM directly, as all the answers to similar problems suggest, here is my solution. It is SO simple.
You could use clipboard API. First you add the text to the clipboard with:
navigator.clipboard.writeText('text') It returns a promise in case you need it.
Then you paste the text at cursor position with document.execCommand('paste');
And that's it! In my case, as this was a part of my chrome extension, i also needed to put in the permissions key in manifest.json the following permissions: "clipboardRead", "clipboardWrite"
Good luck!
P.S. As i see tt is a new feature and is not available in IE and Safary.

Related

How to detect if selected text is in an editable area?

The coder's fantasy
I created a simple user script to act very quickly on the text I selected. It goes like this:
I select a word, a website (doesn't have to be a link), or a phrase from, let's say, a p element
When I press the trigger key, the algorithm will try to figure out if it's a website or text. It will open a tab: if it's a website, that's what it'll load; if it's text, it will google it.
The problem shows its ugly head
It works great except when I'm editing text. If I'm editing something I've written in a textarea/input it will fire, potentially losing what I wrote. Fortunately, there's usually cache, or even the site will warn me for having unsaved changes, which saves me from losing whatever I wrote. But it's something to fix.
The challenge
The userscript should only run on text that can't be edited. You'd think it is as easy as not calling the function if the selected text is within a textarea. But there are many ways to display editable content without using classical elements. The "best" filter I've found is to check for document.activeElement.isContentEditable. However, in this very box, that returns false. This is a textarea element, so I can add it to the filter, and I can do so with a few more I can think of. But apart from being an ugly solution, it is not foolproof.
Besides adding a "did you run me by accident?" prompt, is there a better way to do this?
Edit: my current code
If I understand correctly .... here is an example of how to go about it.
if (['TEXTAREA', 'INPUT'].includes(document.activeElement.nodeName)) {
// it is in textarea, input
}
else if (document.activeElement.isContentEditable) {
// it is in contentEditable element
}
else {
// not above
}
Above is not the only method, e.g. the following using window.getSelection():
const sel = window.getSelection();
const text = sel.toString();
if (!text.trim()) {
// there is no selection
// or selection is white-space
// or selection is in textarea, input
}
else if (document.activeElement.isContentEditable) {
// it is in contentEditable element
}
else {
// not above
}

re announce a <p> under aria-live even if the text is same

I am implementing a search box. One of the scenarios is that the total count of results must be announced. To achieve this I put the <p> tag inside of an aria-live region, and it announces it as expected.
Expected scenario:
User types a string --> hits enter --> results appear and string is announced.
The edge case is if the user hits enter twice.
If the user presses enter again without any changes, nothing is updated since the count is still the same and nothing is announced.
I tried using this on enter click:
if (document.getElementById("header")) {
const currentText: string = document.getElementById("header").innerHTML;
document.getElementById("search-header").innerHTML = "";
document.getElementById("search-header").innerHTML = currentText;
}
But, it still did not announce.
Is there another way to accomplish this?
I ran into a similar situation recently. You've already implemented half of the solution (resetting the innerHTML to an empty string, then setting it to the currentText). The other half of the solution is to set the aria-relevant attribute to all.
By default the aria-relevant attribute is set to additions text, but that leaves out the removed option. Since you need the screen reader to pickup the change to an empty string (when you remove the text), you need to set the attribute to all (which is the same as additions text removed).
As a best practice the aria-relevant attribute should normally be left alone, but I haven't found another way to get the screen reader to make the same announcement twice.
In your case I would also add the aria-live property directly to the element with an id="search-header". It should look something like this:
<h6 id="search-header" aria-live="polite" role="status" aria-relevant="all">
X items found
</h6>
You can read more about the aria-relevant attribute here.
And, there's more information about aria-live regions here.
I faced the same issue. I modified the string with the addition of period, in the end, if the same string is added again to the aira-live div.
I compared the new text value with the existing one in tag, if the value is same then I added period (.) to the incoming string.
if (msg == $(".aria-live-div").text()){
msg = msg + "."
}

Using a Chrome extension to replace characters spanning more than one line in a Facebook status update

I have created a Google Chrome extension to allow users to select text in a component. This works great for most sites. However, Facebook handles its status updates differently. It seems that even though you are filling in what seems to be a single text box, it is actually using a div > div > span > span construct for every single line in this text box. I have no idea why they chose to do this but it makes replacing multiple lines of text much more complex.
Is there a way to select multiple lines (or even contiguous portions of multiple lines) of text in a Facebook status update and replace the data?
The relevant portion of my code looks like this:
function replace_text(language){
let selection = window.getSelection();
string = selection.toString();
/* This section contains code that uses string.replace to replace characters in the string. */
document.execCommand("insertText", false, string);
}
Based on the way my code works now, if I replace text on a single line I have no problems. But, if I replace text that spans multiple lines I end up with a blank unusable input box. Undoubtedly it is because it is removing portions of the html code. How can I fix my code so that the replacement process works properly not only for other sites but also for Facebook?
As of this moment, the one common theme among all status updates (and comments) are that their texts reside within a single or set of span elements with the attribute data-text set to true. So let's target those:
document.querySelectorAll("span[data-text='true']");
For me, I've typed into the status field 3 lines and comment field 1 line of dummy text. So when I execute the above code into the console it returns an array of those four cumulative lines:
>>> (4) [span, span, span, span]
With that array, I can use the Array.prototype.forEach() method to iterate through the spans and replace the innerText:
document.querySelectorAll("span[data-text='true']").forEach(function(element) {
element.innerText = element.innerText.replace('Lorem ipsum','Hello world');
});
However, it is important to note that these changes are being made in the HTML itself and Facebook doesn't store all of its data directly in the HTML. Therefore it can cause undesirable events to occur when you type text into a field, unfocus, change the text in the field, and refocus that field. When you refocus I believe it grabs data of what the text was, before you unfocused that field, from an ulterior source like React's Virtual DOM. To deter it from doing that, the changes either need to be made after clicking the field (real or simulate) or as the user is typing using some sort of MutationObserver (src).

use window.getSelection get selected or cursor located text line from textarea

I am dynamically filling textarea using Ajax call's. In my code, I want to get the cursor's current line content using window.getSelection. I tried following code,
var range = window.getSelection().toString;
alert (typeof(range));
But, It returns function as alert Message. or Any other better way, to get the cursor's current line content from textarea that code need to support in all browser's.? Once I get the current line content I will find out line number and update new content on it.
Firstly, textareas have a different selection API from regular content: use selectionStart and selectionEnd properties of the textarea rather than window.getSelection().
Secondly, getting the current line requires some creative coding if you're accounting for the browser's auotmatic wrapping of content. I've seen a few questions about this in Stack Overflow. Here's one example:
finding "line-breaks" in textarea that is word-wrapping ARABIC text

How to change and track changes to a textarea

I found it really hard to come up with a question title for this one so I apologise that it's fairly cryptic but I'll try explain better there.
Basically part of an app I'm developing involves placing 'placeholders' in a textarea and then modifying those placeholders outside of the textarea.
For example:
This is the <first> placeholder. This is the <second> placeholder.
This is the <first> placeholder again.
Basically i have JS that detects these placeholders and creates input boxes to hold the text. So there would be an input text box for first and one for second.
What I want to achieve is when I type a value into the textbox it changes the placeholder in the textarea to the content being typed into the textbox. Think sublime text editor's snippets for a textarea.
I'm trying to figure out how I can track the placeholders in the text area. For example if a placeholder was <first_name> and i started typing into the placeholders textbox 'Billy'. I could easily change the placeholder by using a string replace function. However now the placeholder <first_name> doesn't exist in the textarea and so now I can't go back and change it. I need to have a way of tracking these placeholders whilst they are changing.
I hope that makes sense.
If you're not bound to a <textarea> element, you can try with a simple div with the attribute contenteditable="true". This way you can use some <span> to mark all the placeholders.
I set up a demo on jsfiddle, try it.
Using an element with contenteditable="true" would be easier for that task, because you could represent placeholders as span elements and you would then only have to retrieve them by id or any other unique attribute to update their content.
If you have to use a textarea and the users can only modify it's content using external inputs, maybe you could initially track the index of each placeholers and their length and keep those synchronized as values are changed.
You could then easily replace content in the textarea. For example, if the placeholder starts at 15 and has a length of 13.
var string = 'this is a test {placeholder} bla bla bla',
placeHolderIndex = 15,
placeHolderLength = 13;
string =
string.substring(0, placeHolderIndex)
+ 'new value'
+ string.substring(placeHolderIndex + placeHolderLength);
//update indexes of every placeholders that comes after this
//one and update the content length of this placeholder.
Obviously, you don't want to hardcode any values and you will want to handle this process in a dynamic way, but that's just an example.
NOTE: I guess users can modify the textarea content if you're using one. In that case, it would make things a bit more complicated, because you would have to update the index of the placeholders for every modifications the user does and you would also have to prevent them from editing the placeholders-mapped text directly.

Categories