How to create a scripted button in Google Sheets that randomly selects from a cells drop-down menu? - javascript

I'm working on a grossly complex and embarrassingly ungraceful spreadsheet that is a crudely crafted prompt-builder for AI image creation tools such as Stable Diffusion. The prompt builder is simply made up of about 40 data-validated drop-down menus that each pull from their respective categorical lists of words and phrases that I have listed elsewhere in the same sheet.
I would like to:
Create a scripted button that would automatically choose random options from the drop-down menus and
Add a probability percentage to each of the drop-down menus so that when the randomize button is pressed, there's a, for example, 100% chance that one option is randomly selected, and a 50% chance that another option will be randomly selected.
The Problem: I created a button, scripted it, and it does not function.
Simplified Editable DEMO of my Prompt Builder
I'm very aware that I'm likely doing this the hard way, and would love to avoid scripting if possible, but am at the end of my limited spreadsheet knowledge. I honestly have no business scripting. Using the script I built currently requires permission for anyone to use, which seems unnecessary to me, but it's the only way I knew to create it. I'm wondering if there's some way around that, maybe with triggers? I suppose that's a separate question...
I'm embarrassed to show this, but this is the script that I cobbled together. Before I added the if statements in trying to add probability, I had it kind of working. It would randomize entries, but some more than others. It was bizarre. Once I added in what I thought was probability code, it completely stopped working. Also, again, this is a simplified version of my actual spreadsheet and script, which had 40 individual data-validated dropdown menus.
My Non-Functioning Script:
function randomSelection() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Prompt Tool Demo");
var cell1 = sheet.getRange("C4");
var cell2 = sheet.getRange("C5");
var cell3 = sheet.getRange("C6");
var values1 = sheet.getRange("K3:K24").getValues();
var values2 = sheet.getRange("L3:L24").getValues();
var values3 = sheet.getRange("M3:M24").getValues();
var randomIndex1 = Math.random();
var randomIndex2 = Math.random();
var randomIndex3 = Math.random();
if (randomIndex1 < 1.0) {
cell1.setValue(values1[Math.floor(Math.random() * values1.length)][0]);
}
if (randomIndex2 < 0.5) {
cell2.setValue(values2[Math.floor(Math.random() * values2.length)][0]);
}
if (randomIndex3 < 0.5) {
cell3.setValue(values3[Math.floor(Math.random() * values3.length)][0]);
}
}

Related

How to automatically fill table based on certain rules (with JS)

I have shift planning table created by JS and shown to user as html. This table is currently filled by user. I have certain set of rules and when user breaks them, he gets warning and he have to fix them.
I want to create script which fills this table automatically. I know how to do this, but i don't know how to do it so that script obeys all that rules and preferences.
For example. I cant give to all users all morning shifts. I need to have it so that one person have no more that 5 shifts in on week, have at least one free weekend, have no more than 20 shifts per month and have them layed out equaly all over the month (not all shifts at the start)
Is this even possible with javascript? If yes could you please give me some idea how?
My current idea is to use 'IF' to obey the rules, but i need to have some rules on same level, so if i use 'IF' and logical operators, but i am kinda stuck on it for days and i am not certain that this is right way to go.
Fiddle with layout of table
Basic draft of my idea to fill table by rules:
function autoFill() {
var numberOfPeople = people.length;
var days = daysInThisMonth();
var ruleOne = ruleOneFunction(); //boolean
var ruleTwo = ruleTwoFunction(); //boolean
for(var i = 0; i < numberOfPeople; i++) {
for(var j = 1; j <= days; j++) {
if(ruleOne === true && ruleTwo === true) {
//fill table here
}
}
}
};

Adobe Acrobat Pro DC JavaScript field properties not propagating

I have been brought in mid stream on an Adobe Acrobat Pro DC customization project. The goal of this project is to add a warning along the left edge of each page. I have been given a piece of JavaScript that does this with one exception and asked to fix that exception.
The code is:
var inch = 72;
for (var p = 0; p < this.numPages; p++) {
var aRect = this.getPageBox( {nPage: p} );
aRect[0] = 8.25*inch; //how far from the left the box ends
aRect[1] = 0.5*inch; //how high from the bottom the box is
aRect[2] = 7.75*inch; //how far from the left the box starts
aRect[3] = 11.0*inch; //how tall the box is
var f = this.addField("ControlledDoc", "text", p, aRect )
f.rotation = 270;
f.delay = true;
f.textSize = 7.5;
f.textFont = font.HelvB;
f.textColor = color.red;
f.alignment = "center";
f.readonly = true;
f.display = display.visible;
f.delay = false;
}
var myWillSaveScript = 'var f = this.getField("ControlledDoc"); \r'
+ 'f.value = "This is an electronic controlled copy of a paper based document management system. When printed on the copy machine it becomes an uncontrolled paper copy valid until the end of the printing day."; \r';
this.setAction("WillSave", myWillSaveScript);
The problem presents when a document is more than one page in length. The ControlledDoc field is replicated on each page as expected. Each page gets a ControlledDoc#n-1 field, where n is the page number. On the first page, the f.rotation setting is retained and shows up in the UI as the Orientation dropdown in the Properties dialog being set to 270. However, on the second and subsequent pages the Orientation is set to 0. I can manually edit the document and set the Orientation to 270, but that defeats the purpose of automating things with JavaScript.
I am new to controlling Acrobat Pro DC with JavaScript, so I will not be surprised if I am missing something stupid...
What do I need to change to make the rotation setting stick on the second and subsequent pages?
Field properties can be on a field level (the same for all copies of the field, with the same nam), or on a widget level (can be different from copy of the field to copy of the field).
The Acrobat JavaScript documentation has a list of those properties. Unfortunately, those two lists (field level and widget level) do not contain the rotation property. That means, we do not really know whether it is field or widget level. From your description, I get the feeling that it is widget level.
What you may try is to create an individual field for every page. You would do that with the line
var f = this.addField("ControlledDoc." + p, "text", p, aRect) ;
About the delay property: I always use the doc.delay property (instead of the field.delay), and because of that outside of a loop, so that it can provide maximum performance gain. However, if the script exits from within the loop, I would have to set delay to false via the Console. From my experience, this will create all appearances (but in order to find out, we'd have to get onto that page, and then they are created immediately…).
I'm assuming you're on page 1 when you run the script. That's why it looks correct on page one.
The delay property, when false, tells Acrobat to delay updating the appearance of the field until it's set to true. When you add the field to the pages, you're telling Acrobat not to generate appearances until all of the settings are set... that's OK... but then, I suspect, you never visit the subsequent pages so the appearances never get updated for those pages even though the delay property is now set to true. Just pull out the two lines that set the delay property and it should work.

Why are my Questions and Scores updating incorrectly in a JSON based game

So i've built out a small scale jeopardy game, and it all works except for my function that handles the answer (if an answer us submitted).
What I want to happen
When you submit an answer, the question should remove the class unanswered and gain add the corresponding value to the score variable.
What it's currently doing
Upon submitting an answer, the class unanswered stays present(Allowing users to click a question they have answered beforehand). The score update does work*
Except that it takes the first value and applies 100pts to each question, so out of 3 questions, my max is 300 when it should be 600.
Since this is a decently sized app, I'll include a plunkr below, but here are my files:
Handle Answer Function
var category = $(this).parent().data('category');
var value = $(this).data('question');
var score = $('#unanswered').html();
var tempvar = x[category][value];
var answers = $('#answers');
function handleAnswer(){
$('.answer').click(function(){// hide empty the tile, mike it unclickable, update the score if correct, and hide the modal
var tile = $('div[data-category="'+$(this).data('category')+'"]>[data-question="'+$(this).data('question')+'"]')[0];
$(tile).empty().removeClass('unanswered').unbind().css('cursor','not-allowed');
if ($(this).data('correct')){
score += parseInt($(this).data('value'));
}
$('#question-modal').modal('hide');
updateScore();
});
}
Questions.JSON
Fully Working PLUNKR Example
Things I've tried
To be honest, I've built this out 3 different times trying different pathing routes and I can't seem to get them all working together. I've messed with different variables and entire JSON structuring.
Thanks for taking a look, I appreciate any help or direction you can point me to!

What would be a proper Google Script for copying dynamically updating range and pasting in Archive sheet?

I am new to Google App scripting, and I have no prior knowledge of scripting of any type other than basic HTML. However, Google App script didn't pose much of a challenge thanks to this forum.
I am a data analyst, and has been researching on low-cost/open source ways to emulate some of basic Big Data advantages for website publishers. My quest brought me to Google scripts. I have been able to write a few since I got to know about it a week ago.
The objective challenge is:
I have a spreadsheet that dynamically pulls about 1000 rows using IMPORTHTML function. The range automatically refreshes as the source refreshes everyday, so previous day's data is lost. That calls for backing up the data in an archive sheet, so that I can analyze the historical data on time-ranges of choice.
I want to automatically copy the rows and paste them on the top of the archive sheet, just below the range header, so that I don't have to sort the archive by dates, which may be required for data analysis. I also need to check for duplicate rows and remove them--just in case.
First I wrote a script that appended the copied rows below the last row of the archived range. However, sorting by date became necessary, as I had to filter the data by specific date ranges, say 14 days or 7 days, for advanced analysis. So I added a snippet for sorting and another for removing duplicates. It works well, however, sorting takes a long time. And considering thousands of new rows being added everyday, it will continue to take longer. I needed a smarter solution.
So I started writing a script that will (1) detect the number of rows in the source range (2) Insert as many rows below the header of the archive sheet and (3) paste copied range into the newly inserted rows.
I finished writing it, and it works very fast; apparently no sorting is required. However, I was wondering, if there is a way to make it even quicker and smarter and future-proof. Please find the code below. Any suggestion will be highly appreciated.
function myFunction() {
//1. Get data from source sheet of a spreadsheet whose id is known, we will also need the data range's last row number
var firstStep = SpreadsheetApp.openById("ID of Source Spreadsheet");
var ss = firstStep.getSheetByName("Sheet1");
ss.activate();
var myRange = ss.getRange(4, 2, ss.getLastRow() - 3, ss.getLastColumn());
var myData = myRange.getValues();
//'3' subtracted from last row data collector above as first three rows contain static data or blank row in my source sheet. Applied same technique at line 17 below as well. This totally depends on how you position the source range in the source sheet. For exaple, for a range starting at 1,1 on any sheet, no such subtraction woud be required.
var lastRow = myRange.getLastRow() - 3;
//2. Open archive spreadsheet, select the destination sheet, insert exact number of rows of source range and then paste copied range.
var secondStep = SpreadsheetApp.openById("ID of archive spreadsheet");
var newSS = secondStep.getSheetByName("dump1");
newSS.activate();
//2.a Insert Rows as in #lastrow in the new sheet, just below the header at Row 1
newSS.insertRowsBefore(2, lastRow)
//2.b Paste values
newSS.getRange(2, 1, myData.length, myData[0].length).setValues(myData);
//2.c Paste last row number of the copied range in another cell of the same sheet, optional step, just to be sure that last row determination process is right. You may remove this step if you like.
newSS.getRange(1, 15).setValue(lastRow);
/*
//3.a Optional: Script to remove duplicate rows in archive sheet. Will increase the script-run duration considerably.
var data = newSS.getDataRange().getValues();
var newData = new Array();
for(i in data){
var row = data[i];
var duplicate = false;
for(j in newData){
if(row.join() == newData[j].join()){
duplicate = true;
}
}
if(!duplicate){
newData.push(row);
}
}
newSS.clearContents();
newSS.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
*/
}
Anything you can accomplish within Google apps Script itself will be much faster than making calls that need to fetch data from Google's servers or an external server such as requests to Spreadsheets, Docs, sites and so on. Your scripts will run faster if you can find ways to minimize the calls the scripts make to those services.
To speed up a script, read all data into an array with one command, perform any operations on the data in the array and write the data out with one command.
Here's an example:
var cell = sheet.getRange('a1');
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
xcoord = xmin;
colors[y] = new Array(100);
for (var x = 0; x < 100; x++) {
colors[y][x] = getColor_(xcoord, ycoord);
xcoord += xincrement;
}
ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);
You must use the Google's Best Practice, The highlight from Google's List are:
Reduce the number of API calls
When making API calls, batch the requests
Use the Apps Script built in cache service
Do not use UIApp; use HTMLService
Here's a document list best practices that will help you improve the performance of your scripts: https://developers.google.com/apps-script/best_practices#minimize-calls-to-other-services

Scripting Photoshop Difference Blendmode

I regularly have two sets of pictures named the same way and I would like to script the process of checking for differences. I'm looking for a basic check, if there is no differences between the two images, discard one of them, if there is a single pixel difference, keep both. For those who question the wisdom of doing this in photoshop, this is an addition to another script that is already running and this optional check will help reduce the number of files I have to upload. I would appreciate the help.
If you really have to do this in Photoshop, this is how I'd propose it:
var doc1 = app.open(new File("~/Desktop/test1.bmp"));
var doc2 = app.open(new File("~/Desktop/test2.bmp"));
doc2.selection.selectAll();
doc2.selection.copy();
app.activeDocument = doc1;
var newLayer = doc1.paste();
newLayer.blendMode = BlendMode.DIFFERENCE;
var histogram = doc1.histogram;
for (var i = 1; i < histogram.length; ++i) {
if (histogram[i] > 0) {
alert('Different!');
break;
}
}
I paste the second picture into the first one and set the resulting layer's blend mode to difference. If the two pictures are identical, the resulting picture should be all black. I therefore check if any color values apart from 0 have any pixels in the histogram.
I assumed the two images have the same size.

Categories

Resources