Determine visible characters to be highlighted using html source - javascript

I'm using TinyMCE to let users edit and format text, output is html code.
The html is then sent to the server and is pushed to other clients that can follow the edit progress on a webpage, the html is inserted into a div so users can see the format but they are not able to edit.
Now I want the cursor position and any selection the user makes in the editor to show up on the readonly page using highlight(background color) if selected or inserting an empty span with a black border between characters to imitate the cursor position.
I made an attempt using
editor.tinymce().selection.getRng()
which gives me the start and end position of what the user sees(formatting characters are not counted)
Then I traversed the DOM and counted the characters in every text element wrapping the ones selected with a highlight span. This resulted in messy code but worked pretty well until I hit a non ascii or encoded character in the textblock.
Example html
<p>abc <b>de</b>fg</p>
looks like this to the user
abc defg
Say user selected character c to d (selection covers c, a blank, first half of the bold tag and d),
tinymce will return range start:2 end:5
but the actual characters behind would be start:5 end:16.
Just wrapping the text from char 5 to 16 in a highlight span will result in bad html.
Checking for words starting with & and ending with ; and adding number of positions will turn into a mess. There has to be a simpler way
How do I calculate how many "visible" characters a set of html character will turn into?
Or maybe you would attack the problem in another way
Thanks
PS 1
I've looked into the various jquery highlight plugins but they seem to highlight based on a search string. Those does not work in the case user selects one character and that character exists several times, they will then highlight all occurences.

I've tackled this problem in my Rangy library: the TextRange module concerns itself with the text the user sees. It sounds like you need the selectCharacters() and toCharacterRange() methods of Rangy's Range objects.

Related

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).

How do I bind a non-breakspace(alt-288 or  ) upon pressing the space bar in javascript?

I'm using OpenMRS, it's an opensource medical records system. OpenMRS has a built-in html editor and I use this mostly in javascripting ang building the forms. In one of my forms,I have a textarea. My client would like his entries(in paragraph or in list) to be indented in the textarea.
Now when you try indenting the paragraph in the textarea then save the changes and preview the form, the paragraph becomes justified instead of retaining the indented lines.
However, if I try indenting the paragraph using ascii code for non-break space by typing   or pressing alt-288, the paragraph becomes indented thus giving me the desired result. Now, the users don't prefer typing or pressing ascii equivalents coz that'll be hassle on their part.
I'm using mostly javascript and jQuery because it's what openmrs supports. If I could somehow bind the non-break space character upon pressing a key then this will work, but I'm at a lost here. How will I do this in javascript or jquery?
One solution which might work for you is to replace leading spaces in the textarea when you process/save or even each time it changes it something like :
ta.value = ta.value.replace (/\n +/, function (m) {
return '\n' + Array (m.length).join ('&#160');
});
The Array ... constructs creates an array containing length elements then joins with your non-breakspace character effectively creating a string of that many space chars.
Another possibility is to watch for space characters entering the text-area and transforming them. See here : Can I conditionally change the character entered into an input on keypress?

How to find cursor row in TextArea in JS when it has soft-wrapped lines?

I have a textarea which I interact with using jQuery. I have some custom keydown event handlers. To make my interactions smooth I could use a function that returns "current cursor row".
One might think that there's a simple solution (proposed on countless SO questions)...
get current cursor position (cross browser plugins exist)
get TEXTAREA value substring up to that cursor position
count newline characters ('\n') in that substring
Problem? This doesn't work when textarea is soft-wrapped. Counting "\n" will produce numbers that are too low.
Question: how do I get the actual precise cursor row number in soft-wrapped textarea? (Precision is key to make my interaction smooth.)

insert double quotes around selected text in xcode

Is there a keystroke to add double quotes around a selection in xcode?
I have snippets #"<#string#>" (qt) and #"<#string#>"<#, #> (qtc)(for making a list in array I use keystroke qtc+enter word tab enter qt+enter...) that I use when I am typing, but I also could use some sort of a macro that I could highlight the word, tap a keystroke, and it would add #"" around it. It seems a little easier. Once you enter the first qtc then you just need qt enter to get the next one from the code popup.
Is there a macro that would put the quotes around the current word the cursor is on? I have seen something like this in TextMate.
This would be a little convenience that would be nice when I am adding a list of words to an array or something and putting the quotes around all the words.
Maybe a little javascript to put in a webpage that would loop though and put the quotes each word in a list would be useful. Or better yet an applescript or some sort of macro that could be used in xcode that would loop through words in a selection and add #"", around each word that could be triggered with a keystroke. Then you could just type a list and select it and tap a keystroke and you just saved a ton of typing.
I found this applescript that replaces text webpage:
http://foolsworkshop.com/applescript/2008/05/an-applescript-replace-text-method/
If you use that you can use applescript with a list separated by commas copied to the clipboad:
set theText to the clipboard
set theReplacedText to replaceText(", ", "\", #\"", theText)
return theReplacedText
then copy the results to the clipboard and paste them where you want. I'm not sure how to get it to activate with a keystroke and replace the selected text a little more neatly.
Is it not the same as in other languages like so NSString *string = #"Some text here /"Here is the text/" ";

Tabbulation in an <input /> tag?

Is it possible to insert a tabbulation character into an input element?
The task: i have one input, the user types 6 characters, which must look like: 3 characters [empty space] 3 characters.
The problem: the left position of the second 3 characters must not change.
For example:
looks:
MMM [ ] OPS
III [ ] DOS
must look:
MMM [ ] OPS
III [ ] DOS
There must be no manipulation with the font-type.
ty
It makes no sense to me why one would have to align the input ... but I can think of a number of alternative solutions that may make sense depending on what the actual stated requirements are (i.e. what is the reason the input has to be aligned)
You could have a 6 char field (or 7 and include the space) with a "preview" to the right (or below, whatever) that formats and aligns the two 3-char codes as you type in the input field.
You could have two separate input fields, and use javascript to auto-tab between them as you type (tab right when full) or backspace (tab left when field 2 is empty)
You could also use javascript to automatically insert a tab (\t) in your field after 3 chars are typed, or when a space is typed replace it with a tab.
The approach I'd use depends entirely on what the field(s) and 3-letter codes are and why they're being input at this time. For a fixed set of codes I might use select lists instead of input.
Yea, insert a tab character "\t". You can copy-pasta it from a text editor, or use javascript to detect the tab key and use it to insert a tab char. Be careful how you override default behaviors though, as the tab key is used for accessibility purposes.
You can use the \t character escape within the input value:
$(document).ready(function() {
$("#text1").val("MMM\tOPS");
$("#text2").val("III\t\tOPS");
});
Note, however, that I had to use one tabulation character in the first text box and two tabulation characters in the second text box in order to properly align the result.

Categories