Setting dropdown width - javascript

How to set the dropdown width to the longest string length in the list of dropdown options using <Select>?
To implement in React JS
Tried with React JS but unable to get the solution.

I am assuming you have an array of all dropdown value like this,
const menuValue = [
'Value',
'Value2222222222222222',
'Lorem Ipsum is simply dummy text of the printing and typesetting industry',
];
let say you want to set the width to the 3rd element of the menuValue array (longest element of that array)
for that you need to set your width like,
const length =
menuValue.reduce((text, newText) =>
newText.length > text.length ? newText : text
).length * 10;
and pass it to the width like {width=`${length}px`}
please prefer this link for better understanding.
I hope it resolves your problem.

Related

How to change rich text without losing its format

How can I change the rich text of a field without loosing its format?
When I try to do something as simple as this
var spans = this.getField("My Field").richValue
event.richValue = spans
the text becomes de-formatted: no linebreaks, no paragraphs / indention, different text size, etc.
Is there a way to copy the rich text exactly as it is? My goal would be to replace a part of the text without changing the formatting.
var spans = this.getField("My Field").richValue
for (var i = 0; i < spans.length; i++) {
spans[i].text = spans[i].text.replace(...)
}
event.richValue = spans
You probably can't. If the formatting was added through the Acrobat/Reader Properties bar, you won't be able to duplicate the formatting after a change made via JavaScript. Unfortunately, the richValue property doesn't capture all of the formatting that the Properties bar allows. You can get back the paragraphs by testing the text property of a span to see if it contains a single space. If so, add \n\n to the text property of the span just before it. You won't be able to get back the indents.

Trim tweets from plugin

I am using this Wordpress plugin
https://smashballoon.com/custom-twitter-feeds/demo
I would like to trim the Tweets to 120 characters.
I have no JS skills and very little php - I tried this which I found but I don't know if it's relevant at all.
$twitter_feed = (strlen($twitter_feed) > 120) ? substr($twitter_feed,0,10).'...' : $twitter_feed;
enter code here
I also attempted to edit my working code for trimming my post titles to suit which did not work.
function custom_trim_my_tweet( $twitter_feed ) {
global $uncode_vc_index;
if ( is_singular() && !$uncode_vc_index )
return $twitter_feed;
$twitter_feed = wp_trim_words( $twitter_feed, 9 );
return $twitter_feed;
}
add_filter( 'ctf-tweet-text', 'custom_trim_my_tweet' );
To trim the text using JavaScript:
First you have to select the element using a css selector. It's easiest if you can select the elements using an element id, like so:
var tweet = document.getElementById("my_tweet_id");
Then you can grab the text content of the element with element.innerText
var tweetText = tweet.innerText;
Then you can simple cut the length of the text inside the element using string.substring()
tweet.innerText = tweetText.substring(0, 120);
I honestly think you should try to fix this at the plugin/wordpress/php level rather than cutting text in JavaScript. But if that's what you want to do, then the above methos would work.
EDIT:
In case the tweet elements do not have unique ID's you will have to select all of them and then loop through each and perform the text-cutting. I'll give you an example of how to do that:
You might have to be a bit creative with your css selectors depending on how the tweets are displayed.
In my example I will assume that you have a div with the ID 'tweets' that then holds five separate div elements, one for each tweet, that all have the same class of 'single-tweet'.
First we get all the 'single-tweet' elements:
var tweets = document.querySelectorAll('#tweets .single-tweet');
tweets now contain a node list of the five 'single-tweet' divs.
Then we loop through them with .forEach() and do the text-cutting on each element.
tweets.forEach( (tweet) => {
tweet.innerText = tweet.innerText.substring(0, 120);
})
Now all of the 'single-tweet' elements will contain what's left after you cut the text down to 120 characters.

Select text and add a tag to it

There are a lot of question about this topic on SO but i can't seem to find any solution for my problem so i decide to ask my question. My situation is i have a dropdown list with several option and a textarea inside iframe. When user select some text in the textarea and choose one option from dropdown list then the selected text will have an a tag wrap around it and the option value will become tag href. Here my code:
var optionTag = document.getElementById("option-id");
var optionValue = optionTag.options[optionTag.selectedIndex].value;
var iframe = document.getElementById("my-frame");
var iframeContent = iframe.contentDocument.body.innerHTML.split("<br>")[0];
//get user selected text
var iframeSelection = iframe.contentWindow.getSelection().toString();
// and wrap a tag around it then add href equal to value of option
var aTag = "" + iframeSelection +"";
// replace user selected text with new a tag
iframe.contentDocument.body.innerHTML = iframeContent.replace(iframeSelection,aTag)
This code work but it only replace the first word if that word already exist. For example:
lorem ipsum click dolor sit amet click spum
If user select the second word "click" and choose one option then my code will replace the only the first word "click" and if i have several word "click" it still only replace the first word, but if user select the word "ipsum" or "lorem" then it work fine. I don't know how to fix this please help. Thank!
p/s:
I don't want to replace all the "click" word, i only want to replace exact piece user selected.
The problem is that iframeSelection in your replace() call is "click", not the element you previously selected, so it's replacing the first occurence.
Instead, try getting the range of your selection, deleting it and appending your new element to that range.
var selection = iframe.contentWindow.getSelection();
range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createElement(your_new_element));
I couldn't test without your HTML, a JSFiddle would help.
The problem is that Javascript String.replace() only works like you expect when using it with a RegExp pattern with the global flag set. Luckily, this answer has a nice solution.
Change this:
iframe.contentDocument.body.innerHTML = iframeContent.replace(iframeSelection,aTag);
...into this:
iframe.contentDocument.body.innerHTML = iframeContent.replace( new RegExp(iframeSelection, 'g'), aTag );
What it does is that it converts your search string into a RegExp object with the global flag set, so each occurrence gets replaced.
If your intention was to only replace the exact piece the user had selected it gets more complex, but you can find all the required bits from this answer.

javascript : focusOffset with html tags

I have a contenteditable div as follow (| = cursor position):
<div id="mydiv" contenteditable="true">lorem ipsum <spanclass="highlight">indol|or sit</span> amet consectetur <span class='tag'>adipiscing</span> elit</div>
I would like to get the current cursor position including html tags. My code :
var offset = document.getSelection().focusOffset;
Offset is returning 5 (full text from the last tag) but i need it to handle html tags. The expected return value is 40. The code has to work with all recents browsers.
(i also checked this : window.getSelection() offset with HTML tags? but it doesn't answer my question).
Any ideas ?
Another way to do it is by adding a temporary marker in the DOM and calculating the offset from this marker. The algorithm looks for the HTML serialization of the marker (its outerHTML) within the inner serialization (the innerHTML) of the div of interest. Repeated text is not a problem with this solution.
For this to work, the marker's serialization must be unique within its div. You cannot control what users type into a field but you can control what you put into the DOM so this should not be difficult to achieve. In my example, the marker is made unique statically: by choosing a class name unlikely to cause a clash ahead of time. It would also be possible to do it dynamically, by checking the DOM and changing the class until it is unique.
I have a fiddle for it (derived from Alvaro Montoro's own fiddle). The main part is:
function getOffset() {
if ($("." + unique).length)
throw new Error("marker present in document; or the unique class is not unique");
// We could also use rangy.getSelection() but there's no reason here to do this.
var sel = document.getSelection();
if (!sel.rangeCount)
return; // No ranges.
if (!sel.isCollapsed)
return; // We work only with collapsed selections.
if (sel.rangeCount > 1)
throw new Error("can't handle multiple ranges");
var range = sel.getRangeAt(0);
var saved = rangy.serializeSelection();
// See comment below.
$mydiv[0].normalize();
range.insertNode($marker[0]);
var offset = $mydiv.html().indexOf($marker[0].outerHTML);
$marker.remove();
// Normalizing before and after ensures that the DOM is in the same shape before
// and after the insertion and removal of the marker.
$mydiv[0].normalize();
rangy.deserializeSelection(saved);
return offset;
}
As you can see, the code has to compensate for the addition and removal of the marker into the DOM because this causes the current selection to get lost:
Rangy is used to save the selection and restore it afterwards. Note that the save and restore could be done with something lighter than Rangy but I did not want to load the answer with minutia. If you decide to use Rangy for this task, please read the documentation because it is possible to optimize the serialization and deserialization.
For Rangy to work, the DOM must be in exactly the same state before and after the save. This is why normalize() is called before we add the marker and after we remove it. What this does is merge immediately adjacent text nodes into a single text node. The issue is that adding a marker to the DOM can cause a text node to be broken into two new text nodes. This causes the selection to be lost and, if not undone with a normalization, would cause Rangy to be unable to restore the selection. Again, something lighter than calling normalize could do the trick but I did not want to load the answer with minutia.
EDIT: This is an old answer that doesn't work for OP's requirement of having nodes with the same text. But it's cleaner and lighter if you don't have that requirement.
Here is one option that you can use and that works in all major browsers:
Get the offset of the caret within its node (document.getSelection().anchorOffset)
Get the text of the node in which the caret is located (document.getSelection().anchorNode.data)
Get the offset of that text within #mydiv by using indexOf()
Add the values obtained in 1 and 3, to get the offset of the caret within the div.
The code would look like this for your particular case:
var offset = document.getSelection().anchorOffset;
var text = document.getSelection().anchorNode.data;
var textOffset = $("#mydiv").html().indexOf( text );
offsetCaret = textOffset + offset;
You can see a working demo on this JSFiddle (view the console to see the results).
And a more generic version of the function (that allows to pass the div as a parameter, so it can be used with different contenteditable) on this other JSFiddle:
function getCaretHTMLOffset(obj) {
var offset = document.getSelection().anchorOffset;
var text = document.getSelection().anchorNode.data;
var textOffset = obj.innerHTML.indexOf( text );
return textOffset + offset;
}
About this answer
It will work in all recent browsers as requested (tested on Chrome 42, Firefox 37, and Explorer 11).
It is short and light, and doesn't require any external library (not even jQuery)
Issue: If you have different nodes with the same text, it may return the offset of the first occurrence instead of the real position of the caret.
NOTE: This solution works even in nodes with repeated text, but it detects html entities (e.g.: ) as only one character.
I came up with a completely different solution based on processing the nodes. It is not as clean as the old answer (see other answer), but it works fine even when there are nodes with the same text (OP's requirement).
This is a description of how it works:
Create a stack with all the parent elements of the node in which the caret is located.
While the stack is not empty, traverse the nodes of the containing element (initially the content editable div).
If the node is not the same one at the top of the stack, add its size to the offset.
If the node is the same as the one at the top of the stack: pop it from the stack, go to step 2.
The code is like this:
function getCaretOffset(contentEditableDiv) {
// read the node in which the caret is and store it in a stack
var aux = document.getSelection().anchorNode;
var stack = [ aux ];
// add the parents to the stack until we get to the content editable div
while ($(aux).parent()[0] != contentEditableDiv) { aux = $(aux).parent()[0]; stack.push(aux); }
// traverse the contents of the editable div until we reach the one with the caret
var offset = 0;
var currObj = contentEditableDiv;
var children = $(currObj).contents();
while (stack.length) {
// add the lengths of the previous "siblings" to the offset
for (var x = 0; x < children.length; x++) {
if (children[x] == stack[stack.length-1]) {
// if the node is not a text node, then add the size of the opening tag
if (children[x].nodeType != 3) { offset += $(children[x])[0].outerHTML.indexOf(">") + 1; }
break;
} else {
if (children[x].nodeType == 3) {
// if it's a text node, add it's size to the offset
offset += children[x].length;
} else {
// if it's a tag node, add it's size + the size of the tags
offset += $(children[x])[0].outerHTML.length;
}
}
}
// move to a more inner container
currObj = stack.pop();
children = $(currObj).contents();
}
// finally add the offset within the last node
offset += document.getSelection().anchorOffset;
return offset;
}
You can see a working demo on this JSFiddle.
About this answer:
It works in all major browsers.
It is light and doesn't require external libraries (apart from jQuery)
It has an issue: html entities like are counted as one character only.

Can't get document.getElementById.getElementsByTagName to work properly

function confirm_results(theform) {
var inputsX = document.getElementById(theform).getElementsByTagName('textarea');
for(var iX = 0, nX = inputsX.length - 1; iX < nX; iX++)
{
text += inputs[iX].innerHTML + ', ';
}
return text;
}
Can anyone tell me why this isn't working? I'm trying to find all of the textarea's inside a DIV that I pass the name through, and return the text. Some reason it just doesn't do anything.
innerHTML is not the right way to read a textarea's value.
Partly because any < or & characters in it will be HTML-escaped, but mostly because the text node content inside an HTMLTextAreaElement node is not indicative of the current value of the textarea.
In fact the text node content is the original content of the textarea as seen in the HTML source. This is the same as the defaultValue property. It does not get updated when you type in the textarea... except in IE which as usual gets it all wrong.
You probably want to use inputs[iX].value instead.
The same goes for normal inputs, where input.value represents the current value but input.getAttribute('value') is the same as input.defaultValue, representing the original value put in the value="..." attribute in the HTML source. Again: except in IE due to more bugs.
The same again applies to the checked and selected properties of checkboxes and select options: the checked and selected attributes are the original values reflected in the defaultChecked and defaultSelected properties.
Also, with the length-1 you're ignoring the last textarea in the list. Do you really mean to do that?

Categories

Resources