Creating Rainbow Text in Google Docs - javascript

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.

Related

Can I divide a text box by paragraph in Google Slides using Apps Script?

I am trying to design some code in Apps Script that can be put on any Google Slides presentation and split every text box by paragraphs so every paragraph has its own text box.
I started out using var shape = slide.insertShape(SlidesApp.ShapeType.TEXT_BOX, 50, 50, 300, 300); to make the new text boxes like google describes to use in most of its tutorials but it 'couldn't identify the TEXT_BOX type' so I found .insertTextBox and that seems to work better but I've found other problems.
I can use .getParagraphs to find the number of paragraphs in a text box but I can't tell if it doesn't include the contents of each paragraph or if I'm just not using the correct command to get the text from the paragraph. I have also tried to find an alternative to find the beginning of each paragraph and divide the text from there but I can't find a command for that either. Maybe would I have to use .indexOf to find each /n or /r, or is there a simpler way?
I'm also having a problem where my equations to divide up the text box size are giving me undefined answers and I've tried declaring the variables as numbers but it just makes things worse.
function myFunction() { // get slides in the presentation and establish 'for' variables
var slide = SlidesApp.getActivePresentation().getSlides();
var i;
var j;
var k;
for (i = 0; i < slide.length; i++) { // get the text boxes on each slide
var text = slide[i].getShapes();
for (j = 0; j < text.length; j++) { // get the location of and the paragraphs in each textbox (locations don't work)
var top = text[j].getTop;
var left = text[j].getLeft;
var width = text[j].getWidth;
var height = text[j].getHeight;
var paragraph = text[j].getText().getParagraphs();
for (k = 0; k < paragraph.length; k++){ // make a textbox for each paragraph distributed vertically over the original textbox
var content = text[j].getRange(paragraph[k]); //I was hoping this would fill with the contents of current paragraph
var shapeheight = height / paragraph.length; //NaN and I don't know why
var shapetop = height * k + top; //also doesn't work these should all be numbers
slide[i].insertTextBox(content, left, shapetop, width, shapeheight);
}
text[j].remove(); //delete original textbox on slide
}
}
}
Here are pictures of what I'm trying to do:
Slide before intended changes
Approximate slide after intended changes
I believe your goal as follows.
You want to split each paragraph in a text box as each text box on Google Slides.
You want to achieve this using Google Apps Script.
Modification points:
In your script,
getTop, getLeft, getWidth and getHeight are the method. So please add ().
About var content = text[j].getRange(paragraph[k]), getRange has no arguments.
About var shapeheight = height / paragraph.length, in this case, this can be put outof the for loop.
About var shapetop = height * k + top, in this case, that might be var shapetop = shapeheight * k + top.
When above points are reflected to your script, it becomes as follows.
Modified script:
function myFunction() {
var slide = SlidesApp.getActivePresentation().getSlides();
var i;
var j;
var k;
for (i = 0; i < slide.length; i++) {
var text = slide[i].getShapes();
for (j = 0; j < text.length; j++) {
var top = text[j].getTop(); // Modified
var left = text[j].getLeft(); // Modified
var width = text[j].getWidth(); // Modified
var height = text[j].getHeight(); // Modified
var paragraph = text[j].getText().getParagraphs();
var shapeheight = height / paragraph.length; // Modified
for (k = 0; k < paragraph.length; k++) {
var content = paragraph[k].getRange().asString(); // Modified
var shapetop = shapeheight * k + top; // Modified
slide[i].insertTextBox(content, left, shapetop, width, shapeheight);
}
text[j].remove();
}
}
}
Note:
In the current stage, it seems that AutoFit cannot be set. By this, when slide[i].insertTextBox(content, left, shapetop, width, shapeheight) is used, the text deviates a little from the box. So in this case, how about not using shapeheight? In this case, please modify slide[i].insertTextBox(content, left, shapetop, width, shapeheight); as follows.
var t = slide[i].insertTextBox(content);
t.setLeft(left);
t.setTop(shapetop);
t.setWidth(width);
References:
getTop()
getLeft()
getWidth()
getHeight()
getRange()
insertTextBox(text)

How to set part of string bold?

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.

Change cells background colour if array contains innerHTML

I'm trying to change those cells background colour that innerHTML values match with my array. How can i make it?
var numbers = ["15628","15623","15656","11628"];
var table = document.querySelector("[name='main']")
.contentWindow.document.getElementById("music").rows.length;
for (i = 4; i < table -1; i++){
if (document.querySelector("[name='main']")
.contentWindow.document.getElementById("music").rows[i].cells[1].innerHTML == numbers)
{
document.querySelector("[name='main']")
.contentWindow.document.getElementById("music")
.rows[i].cells[1].style.backgroundColor = "yellow";
};
Are you sure this element select is correct: document.querySelector("[name='main']").contentWindow.document.getElementById("music").rows[i].cells[1] ?
It hard analize without looking to html.
If it OK, maybe you need such solution:
for (i = 4; i < table -1; i++){
let value = document.querySelector("[name='main']")
.contentWindow.document.getElementById("music").rows[i].cells[1].innerHTML;
if (numbers.includes(value))
{
document.querySelector("[name='main']")
.contentWindow.document.getElementById("music")
.rows[i].cells[1].style.backgroundColor = "yellow";
};

How to select text in 2nd line of Textbox element by using FabricJS?

I'm wondering if there is a way to select part of a text in Textbox element of FabricJS?
Currently, I'm using
text.selectionStart = 0;
text.selectionEnd = 4;
but it selects text in the first line (makes sense why).
How to let fabric know that I need to select those from the second line?
Tnx
http://jsfiddle.net/redlive/4n4cLyvo/
You can use the insertCharStyleObject method available in fabric.
Code snippet :
var selectionStart = 0;
var selectionEnd = 4;
var lineIndex = 1;
for (var i = selectionStart; i < selectionEnd; i++) {
text.insertCharStyleObject(lineIndex, i, {
textBackgroundColor: '#0F0'
})
}
Updated fiddle - http://jsfiddle.net/4n4cLyvo/2/

How to add marquee element with text to a div in javascript

I have an array of line_items which contain some text, i have 9 div with id like <div id="scroller-1"></div> and scroller-2 and so on...
what i want to do is i am iterating through array and getting text, but i want to add first element to div with scroller-1 id, second element to scroller-2 and so on like for all 9 divs. how can i do that
var trending_cat = [
["Lotto Rapid Running Shoes"],
["Paradise (English) (Paperback)"],
["Canon EOS 700D (Body with 18-135 mm Lens) DSLR Camera"],
["Huetrap Graphic Print Men's Round Neck T-Shirt"],
["Vincent chase vc 5158 silver silver reflector mirror ao12jo aviator sunglasses"],
["Orka XL Bean Bag With Bean Filling"],
['HP Compaq 15-s103TX Notebook (4th Gen Ci3 4GB 1TB Free DOS 2GB Graph) (K8T82PA)'],
['Moto G (2nd Generation) White, 16 GB'],
['Fastrack 9827PP01 Hip Hop Analog Watch - For Women'],
];
javascript:
for (var i = 0; i < trending_cat.length; i++) {
var cato = trending_cat[i][0];
}
i want to append the value like this
<marquee scrollamount="38"><strong><h1>[i][0]</h1></strong></marquee>
There are a couple of ways. If there's a CSS selector that matches the elements in the order you want to apply them, it's really easy:
var list = document.querySelectorAll("the-css-selector");
for (var i = 0; i < trending_cat.length; i++) {
list[i].innerHTML = trending_cat[i][0];
}
If you need to work with id values in the form scroller-1 through scroller-9, it's also really straightforward:
for (var i = 0; i < trending_cat.length; i++) {
document.getElementById("scroller-" + (i + 1)).innerHTML = trending_cat[i][0];
}
Both of those assume you want to interpret the strings as HTML. If you want them interpreted as pure text, cross-browser issues make it a bit more complicated (but not much).
var list = document.querySelectorAll("the-css-selector");
for (var i = 0; i < trending_cat.length; i++) {
list[i].innerHTML = "";
list[i].appendChild(document.createTextNode(trending_cat[i][0]));
}
Or with the ids:
var element;
for (var i = 0; i < trending_cat.length; i++) {
element = document.getElementById("scroller-" + (i + 1));
element.innerHTML = "";
element.appendChild(document.createTextNode(trending_cat[i][0]));
}
In both cases, we can be more succinct using Array#forEach:
var list = document.querySelectorAll("the-css-selector");
trending_cat.forEach(function(cato) {
list[i].innerHTML = "";
list[i].appendChild(document.createTextNode(cato));
});
(And similarly for the ids version.)
If you rearrange the html tag so that the marquee is in the center, you can insert the text without worrying about overwriting the h1 and strong tags. E.g.,
<strong><h1><marquee id="scroller-0" scrollamount="38"></marquee></h1></strong>
Also, your strings inside trending_cat do not have to be in separate arrays. This is fine:
var trending_cat = [
"Lotto Rapid Running Shoes",
// etc
];
You can use a for-loop to set the values:
for (var i=0; i<8; i++) {
document.getElementById("scroller-"+i).innerText = trending_cat[i];
}
Here is a running example: https://jsfiddle.net/dxv1x419/2/

Categories