How to set part of string bold? - javascript

I want to take a string from a cell and examine it for keywords. These keywords should then be marked Bold and the complete string should be returned with the Bold marked keywords. Here is an example:
=boldKeywords("I am an example text", "text")
Result: I am an example text.
The script works so far. I am just not possible to make the keywords bold. This should happen here: "//splitString[i] should be set bold". Here is the script:
function boldKeywords(text, keywords) {
// Split the test and the keywords into an Array with single Strings
var splitString = text.split(" ");
var splitKeywords = keywords.toUpperCase().split(", ");
//Go through the array and compare each word to the keywords
for(var i = 0; i < splitString.length; i++){
for(var j = 0; j < keywords.length; j++){
if(splitString[i].toUpperCase().localeCompare(splitKeywords[j]) == 0){
//splitString[i] should be set bold
}
}
}
//Concatenate Array Sting to one String
var retunString = "";
for(var j = 0; j < splitString.length; j++) {
retunString = retunString + " " + splitString[j];
}
//return String
return retunString;
}

To make parts of a cell content bold, you need to use RichText
As mentioned by Marios, you cannot use RichText in a custom formula, so you have to modify your set-up a bit.
for example, you can write your key word(s) into a free cell (e.g. A1) and create a custom button to which you can assign the following script:
function boldKeywords() {
var cell = SpreadsheetApp.getActive().getActiveSheet().getActiveCell();
var text = cell.getValue();
var keywords = SpreadsheetApp.getActive().getActiveSheet().getRange("A1").getValue();
// Split the test and the keywords into an Array with single Strings
var splitString = text.split(" ");
var splitKeywords = keywords.toUpperCase().split(", ");
var value = SpreadsheetApp.newRichTextValue();
value.setText(text);
var position = 0;
for(var i = 0; i < splitString.length; i++){
for(var j = 0; j < splitKeywords.length; j++){
if(splitString[i].toUpperCase().localeCompare(splitKeywords[j]) == 0){
var start = text.indexOf(splitString[i], position)-1;
var end = start + splitString[i].length+1;
var bold = SpreadsheetApp.newTextStyle().setBold(true).build();
value.setTextStyle(start, end, bold);
}
}
position += splitString[i].length+1;
}
var values = value.build();
cell.setRichTextValue(values);
}
This script will mark all the keywords bold for the cell that is being selected at the moment you press on the button.
Note that if you expect to encounter more than once in a cell, it is important to define position to correctly highlight all instances of a keyword as bold.

Unfortunately, custom functions can not return formatted data.
This issue has been reported already in the IssueTracker. You can click on the star button to the top left of the page to increase the chances of this feature to be implemented by Google.
Potential workarounds:
You can create a button/menu to execute a regular function that will be able to set the format and the value of the selected cell.
You can use an onEdit() trigger to set the format and the value of the cell when you edit that cell or when you click on a checkbox for example.
You can set up a time-driven trigger to change the format of the cell when the cell hasn't been formatted properly.

Related

Looping through array and back to beginning when reaching end

I have a simple array
var answerAttribute = ['A','B','C','D'];
I have 16 list items, what I'm trying to accomplish is loop through the length of the list and regardless of if the list 2 items or 300. I'd lke to have a data attribute associated with it of A,B, C or D.
Here's what I'm working with:
var questionOption = '';
for(var i = 0; i < quizContent.length; i++) {
questionOption = answerAttribute[i % answerAttribute.length];
console.log(questionOption);
}
When logging this to the console, it logs A, AB, ABC, ABCD, ABCDundefined, and keeps repeating undefined until it's reached the loops conclusion. My question is what am I doing incorrectly so that it only logs one letter per loop.
questionOption += answerAttribute[i]
This statement is short-form for questionOption = questionOption + answerAttribute[i]. It will append the next element to questionOption in every iteration of the loop.
It looks like what you want is probably questionOption = answerAttribute[i]. This will replace the value in questionOption with the new element instead of appending it.
You could simply log only the current value, like this:
var questionOption = '';
for (var i = 0; i < quizContent.length; i++) {
//what is questionOption used for?
questionOption += answerAttribute[i];
console.log(answerAttribute[i]);
}
or if you want questionOption to refer to the current value
questionOption = answerAttribute[i];
console.log(questionOption );
You're looping the quizContent indexes and applying them to the answerAttribute array. I believe what you want is a nested loop...
var quizContent = Array(10); // assume you have 10 quiz questions...
var answerAttribute = ['A','B','C','D'];
for (var i = 0; i < quizContent.length; i++) {
// generate a string for each quiz option
var questionOption = '';
for (var n = 0; n < answerAttribute.length; n++) {
questionOption += answerAttribute[n];
}
quizContent[i] = questionOption;
console.log(questionOption);
}
console.log(quizContent);
Somehow I doubt that the question is actually about the logging, and is actually about the resulting string.
Either way, I'd do this without loops.
var answerAttribute = ['A','B','C','D'];
var quizContent = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1];
var questionOption = answerAttribute
.join("")
.repeat(Math.ceil(quizContent.length / answerAttribute.length))
.slice(0, quizContent.length);
console.log(questionOption);
It just joins the answerAttribute into a string of characters, and repeats that string the number of times that the length of answerAttribute can be divided into quizContent.length (rounded up).
Then the final string is trimmed down to the size of the quizContent to remove any extra content from the rounding up.
Note that this approach assumes a single character per attribute. If not a single, but they're all the same length, it can be adjusted to still work.

Filter table data from first character of string in jquery/javascript

I have a table with some records and a textbox. I want to filter table data based on string entered in textbox on keyup event.
Currently I am using a code block which filter the table data but it search the record in table which exist anywhere in the string.
For example:- If I enter 'ab' in textbox it filter the table record with strings contains the keyword 'ab' like abcd, babd, cdab etc.
But my requirement is when I enter the keyword 'ab' in textbox it search only those string which starts from 'ab' like abcd, abdc etc.
Here is my current code:-
function Search_Gridview(strKey, strGV) {
var strData = strKey.value.toLowerCase().split(" ");
var tblData = document.getElementById(strGV);
var rowData;
for (var i = 1; i < tblData.rows.length; i++) {
rowData = tblData.rows[i].cells[3].innerHTML;
var styleDisplay = 'none';
for (var j = 0; j < strData.length; j++) {
if (rowData.toLowerCase().indexOf(strData[j]) >= 0)
styleDisplay = '';
else {
styleDisplay = 'none';
break;
}
}
tblData.rows[i].style.display = styleDisplay;
}
}
Please help guys......
You can filter with jQuery the columns that contain a string beginning with e.g. "ab" of this way:
var re = $("#TABLE_ID td").filter(function(i){ return this.innerHTML.startsWith("ab") })
//You can after, get the values of each td of the result of this way
re.map(function(i){return this.innerHTML})
You can use RegExp's test method.
var stringData = [
'aaa', 'aab', 'aac',
'aba', 'abb', 'abc'
];
var searchPrefix = 'ab';
var result = stringData.filter(function (str) {
// return true if str has prefix with searchPrefix.
return (new RegExp('^' + searchPrefix)).test(str);
});
console.log(result);
JavaScript Regexp Reference
This appears the most elegant solution.
To change search behavior from "exists anywhere in the data" into "data starts with ". You only need to change one single character, on one single line of your original code and nothing more.
Change this line from this..
if (rowData.toLowerCase().indexOf(strData[j]) >= 0)
into this...
if (rowData.toLowerCase().indexOf(strData[j]) == 0)
What it does is forces the indexOf() to address zero, instead of allowing mid-string matches.
Below is the whole (already modified) code for copy and paste into a project, such as a html table filter.
function Search_Gridview(strKey, strGV) {
var strData = strKey.value.toLowerCase().split(" ");
var tblData = document.getElementById(strGV);
var rowData;
for (var i = 1; i < tblData.rows.length; i++) {
rowData = tblData.rows[i].cells[3].innerHTML;
var styleDisplay = 'none';
for (var j = 0; j < strData.length; j++) {
if (rowData.toLowerCase().indexOf(strData[j]) == 0)
styleDisplay = '';
else {
styleDisplay = 'none';
break;
}
}
tblData.rows[i].style.display = styleDisplay;
}
}
Search_Gridview() = the function's name.
strKey = input search characters
strGV = ID of html table></table

Creating Rainbow Text in Google Docs

var selectedElements = selection.getSelectedElements();
for (var i = 0; i < selectedElements.length; ++i) {
var selectedElement = selectedElements[i];
// Only modify elements that can be edited as text; skip images and other
// non-text elements.
var text = selectedElement.getElement().editAsText();
// Change the background color of the selected part of the element, or the
// full element if it's completely selected.
if (selectedElement.isPartial()) {
text.setColor(selectedElement.getStartOffset(),
selectedElement.getEndOffsetInclusive(), '#69359c');
}
}
}
The above text takes a selection inside of a Google Doc and changes it to the hex code #69359c (a dark purple). I have searched many websites, many gits, and asked many friends for help with my project.
My end project is this:
Create a menu for Google Docs with my selector (DONE)
Be able to highlight a certain amount of text and change it to an array of colors (ROY G. BIV / the rainbow).
Have the format be only for Google Documents.
If anyone can help me it would be highly appreciated.
I just found this question and am happy to provide some working code from my Rainbow Font Google Docs add-on (Magic Rainbow Unicorns).
The first problem is that you need to set the foreground color on the text, and the second is that the code above only allows for partial paragraph selections.
For whole selections use this code:
var elementText = element.editAsText();
if (elementText) {
var paragraph = elementText.getText();
for (var j = 0; j < paragraph.length; j++) {
elementText.setForegroundColor(j, j, getNextRainbowColour(...));
}
}
For partial selections, I used this:
var elementText = element.asText();
var startIndex = element.getStartOffset();
var endIndex = elements.getEndOffsetInclusive();
for (var j = startIndex; j < endIndex+1; j++) {
elementText.setForegroundColor(j, j, getNextRainbowColour(...));
}
You are pretty close to the answer already. Try iterating over the elements within your 'text' variable, so you can change the background on each one.
You could use something like this to iterate over each letter:
var letters = elementText.getText();
for(var j = 0 ; j< letters.length-1; j++)
{
elementText.setBackgroundColor(j, j+1, getRandomColor())
}
Here is a sample of a function to use different colors:
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ )
{
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
For your last question, since the Text class is not part of Javascript, but from app-script library, this will not work outside Google environment.

Javascript: matching a dynamic string against an array

I'm attempting to teach myself javascript. I chose something I assumed was simple, but ran into problems relatively quickly.
I'm attempting to search a string for another string given by the user.
My code so far is:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = [];
var one = 0;
var two = 0;
var k = 0;
var sourceSearch = function(text) {
for(i = 0; i < source.length; i++) { //for each character in the source
if(source[i] === searchString[0]) { //if a character in source matches the first element in the users input
one = source.indexOf(i); //confused from here on
for(p = searchString.length; p > 0; p--) {
}
}
}
};
sourceSearch(searchString);
My idea was:
check to see if the first loop finds a character that matches the first character in the user input
if it matches, check to see if the next X characters after the first match the next X characters in the source string
if they all match, push them to the hits array
My problem: I have no idea how to iterate along the arrays without nesting quite a few if statements, and even then, that wouldn't be sufficient, considering I want the program to work with any input.
Any ideas would be helpful. Thanks very much in advance.
Note: There are a few un-used variables from ideas I was testing, but I couldn't make them work.
You can try:
if (source.indexOf(searchString) !== -1) {
// Match!
}
else
{
//No Match!
}
As the other answers so far point out, JavaScript strings have an indexOf function that does what you want. If you want to see how it's done "by hand", you can modify your function like this:
var sourceSearch = function(text) {
var i, j, ok; // always declare your local variables. globals are evil!
// for each start position
for(i = 0; i < source.length; i++) {
ok = true;
// check for a match
for (j = searchString.length - 1; ok && j >= 0; --j) {
ok = source[i + j] === searchString[j];
}
if (ok) {
// searchString found starting at index i in source
}
}
};
This function will find all positions in source at which searchString was found. (Of course, you could break out of the loop on the first success.) The logic is to use the outer loop to advance to each candidate start position in source and use the inner loop to test whether that position actually is the position of a match to searchString.
This is not the best algorithm for searching strings. The built-in algorithm is much faster (both because it is a better algorithm and because it is native code).
to follow your approach, you can just play with 2 indexes:
var sourceSearch = function(text) {
j = 0;
for(i = 0; i < source.length; i++) {
if(source[i] === text[j]) {
j++;
} else {
j = 0;
}
if (j == text.length) {
console.log(i - j); //this prints the starting index of the matching substring
}
}
};
These answers are all pretty good, but I'd probably opt for something like this:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = source.split(searchString);
var hitsCount = hits.length - 1;
This way you have all of the data you need to figure out where each hit occurred in he source, if that's important to you.

Adding text to InnerHTML in TDs with Javascript

I am trying to add text to each cell in particular column via Javascript. Like every 8th TD would be processed for adding text.
Tell me what I have done wrong here/why it doesn't appear in my table:
<script type="text/javascript">
window.onload = function inventorytable() {
var tableRows = document.getElementById
("inventorytable").getElementsByTagName("tbody")[0].getElementsByTagName("tr");
for(var i = 0, l = tableRows.length; i < l; i++) {
tds = tableRows.getElementsByTagName("td");
var processor = tds[8].innerHTML += " Ghz"
var ram = tds[9].innerHTML += " GB"
var rspeed = tds[11].innerHTML += " Mhz"
}}
</script>
You've forgotten to refer to the i-th row:
tds = tableRows[i].getElementsByTagName("td");
I recommend to use:
window.onload = function inventorytable() {
var tableRows = document.getElementById("inventorytable").rows;
//or .tBodies[0].rows
for(var i=0, l=tableRows.length; i < l; i++) {
var tds = tableRows[i].cells;
/*processor*/ tds[8].innerHTML += " Ghz"
/*ram */ tds[9].innerHTML += " GB"
/* rspeed */ tds[11].innerHTML += " Mhz"
}
}
Do not define unused variables. If you want to clarify their use, use comments.
Also, I have replaced .getElementsByTagName by .rows and .cells.
Update
JavaScript sets are zero-based. So, if you want to refer to the 4th cell, use .cells[3].
At your previous answer, you've showed a fiddle. see http://jsfiddle.net/ndfh2/.
As you can see, the first row is also getting postfixes. To not add postfixes to these cells in the first row, initiate the counter at one: for( var i=1; .. ; .. )
Your current code does probably not work, because your rows don't have twelve (12) rows. Remember, the number at tds[ number ] equals the index of a cell within a row, starting at zero.

Categories