How to define / existing javascript function in iMacro - javascript

I am new to iMacro so please correct me if my approach with iMacro is incorrect.
I have created some javascript functions that are helpful in testing certain conditions on the DOM. The problem is i am not able to include javascript functions ( from External js file as well as defining on the .js script of imacro ) into my test file and call the functions from js lib during test case execution.

Have you tried using iimGetLastExtract()
You can create a .js file that calls imacros. those macros can extract information that you need from the DOM. using iimGetLastExtract() you can extract those values and test it in the js
when you are in FF you can actually choose a .js file to run from the imacros menu.
Here is an example of an old .js file i used to do just such a thing. im looping through the values of a dynamically created drop down and doing things based on its value. (if a macro fails it will a value less than 0: error codes )
var i = 1;
var notDone = 1;
while(notDone > 0) {
//select the board from available
iimSet('name', boardname);
iimPlay('selectBoard.iim');
//pick the next display view and capture the view name
iimSet('index',i);
notDone = iimPlay('assignDisplay.iim');
var displayName = iimGetLastExtract(1),
inputName = iimGetLastExtract(2),
label = '';
if((displayName == '[None]' && displayName == '[None]') || !notDone) {
break;
}
label = (displayName === '[None]') ? inputName : displayName;
if(prefix) label = prefix + label;
if(suffix) label += suffix;
iimSet('name', label);
iimSet('btn',btn);
iimPlay('assignLabelInput.iim');
i++;
}
If you arent familiar with some of the things in there. im using iimSet() to set variables in the imacros. iimPlay to play that macro. and in the macro itself, here is an example of extracting information
TAG POS=1 TYPE=SELECT FORM=NAME:form1 ATTR=ID:dropdownid EXTRACT=TXT
edit
Here is a silly example that will hopefully show the use of js and the imacros extract functionality
The code
example.js
var allAnswerVotes=[];
var runningTotal = 0;
var working = true;
var i = 2;
while(working) {
iimSet('i', i);
iimPlay('getVotes.iim');
var extract = iimGetLastExtract(1);
if(extract === '#EANF#') {
working = false;
continue; //hault this iteration;
}
var numVotes = parseInt(extract, 10);
allAnswerVotes.push(numVotes);
runningTotal += numVotes;
i++; //increment i to get the next vote
}
alert('The highest vote is '+ Math.max.apply(null, allAnswerVotes)+', with an average of '+ Math.ceil(runningTotal / allAnswerVotes.length));
getVotes.iim
TAG POS={{i}} TYPE=SPAN ATTR=class:*vote-count-post* EXTRACT=TXT
The explanation
First thing to do is make sure that both of these files (example.js, getVotes.iim) are located in the same folder in order for example.js to run getVotes.iim correctly.
next you just have to navigate to any StackOverflow thread, select example.js from the imacros menu (f8 to open the menu) and push play (or simply double click example.js)
the macro will find the i-th position span with class containing "vote-count-post" and return the text of that span. i is a parameter that is passed in by the js. we will start at i = 2, so the second vote span (we are skipping the vote for the question and only counting the votes for answers). the js will continue to call getVotes.iim until getVotes returns an extract value of "#EANF#" which is the return value when the macro cant find the specified tag (i.e. when there are no votes on the current page). #EANF# will kick us out of our loop and then you get the alert with some basic math on the votes we tallied.
The extracting of votes here is pretty silly but I'm just demonstrating a basic example of how to use imacros EXTRACT in js

Related

I used js to create my command syntax, now how can I use it?

I have a Google Sheet with .gs script that is successfully generating dynamicnewRichTextValue() parameters which are meant to be injected into a Sheet cell that will contain multiple lines of text each with their own URL. I do not know all of the parameters in advance (might be one text and one link, or two each, or more) which is why I am dynamically generating the parameters.
Let's say the end-state should be this (in this case there are only two line items, but there could be more or less:
var RichTextValue=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com")
.setLinkUrl(0,6,"mailto:fred#abcdef.com")
.setLinkUrl(7,19,"mailto:jim#abcdef.com")
.build();
In my script I don't know how many "setText" parameters or "setLinkUrl" statements I will need to generate, so I am doing it dynamically.
This is simple to handle for "setText" because I can just pass a single variable constructed during an earlier loop that builds the "setText" parameters. Let's call that variable setTextContent, and it works like this:
var RichTextValue=SpreadsheetApp.newRichTextValue()
.setText(setTextContent)
So up to this point, everything is great. The problem is that I have another variable that generates the URL portion of the newrichtextvalue() parameters up to the ".build();" statement. So let's call that variable setUrlContent and it is built in an earlier loop and contains the string for the rest of the statement:
.setLinkURL(0,22,"mailto:fred#abcdef.com").setLinkURL(23,44,"mailto:jim#abcdef.com")
I am stumped trying to figure out how to attach it to the earlier bit. I feel like this is something simple I am forgetting. But I can't find it after much research. How do I hook up setUrlContent to the code above so that the command executes? I want to attach the bits above and get back to assigning it all to a variable I can put into a cell:
var emailCell=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com") // I can dynamically create up to here
.setLinkUrl(0,6,"mailto:fred#abcdef.com") // ...but these last couple lines are
.setLinkUrl(7,19,"mailto:jim#abcdef.com") // stuck in a string variable.
.build();
sheet.getRange(1,1,1,1).setRichTextValue(emailCell)
Thanks!
I believe your goal and situation as follows.
You want to use your script by dynamically changing the number of emails.
Modification points:
When your following script is run, I think that the links are reflected to mailto and fred#abcdef..
var emailCell=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com")
.setLinkUrl(0,6,"mailto:fred#abcdef.com")
.setLinkUrl(7,19,"mailto:jim#abcdef.com")
.build();
sheet.getRange(1,1,1,1).setRichTextValue(emailCell)
I thought that you might have wanted the linked email addresses like below.
fred#abcdef.com has the link of mailto:fred#abcdef.com.
jim#abcdef.com has the link of mailto:jim#abcdef.com.
In this answer, I would like to propose the modified script for above direction.
Modified script:
var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com"; // This is your sample text value.
var ar = inputText.split(",").map(e => {
var v = e.trim();
return [v.split(":")[1], v];
});
var text = ar.map(([e]) => e).join(",");
var emailCell = SpreadsheetApp.newRichTextValue().setText(text);
var start = 0;
ar.forEach(([t, u], i) => {
var len = t.length;
emailCell.setLinkUrl(start, start + len, u);
start += len + 1;
});
SpreadsheetApp.getActiveSheet().getRange(1,1,1,1).setRichTextValue(emailCell.build());
In this modification, inputText is splitted to the hyperlink and the text (for example, when your sample value is used, it's fred#abcdef.com and mailto:fred#abcdef.com.), and the text including the hyperlink are put to the cell.
In this case, for example, even when var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com" is modified to var inputText = "mailto:fred#abcdef.com" and var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com,mailto:sample#abcdef.com", each hyperlink are reflected to each text.
Note:
When you want to the hyperlink of mailto:fred#abcdef.com to the text of mailto:fred#abcdef.com, you can also use the following modified script.
var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com"; // This is your sample text value.
var ar = inputText.split(",").map(e => e.trim());
var emailCell = SpreadsheetApp.newRichTextValue().setText(inputText);
var start = 0;
ar.forEach((t, i) => {
var len = t.length;
emailCell.setLinkUrl(start, start + len, t);
start += len + 1;
});
SpreadsheetApp.getActiveSheet().getRange(1,1,1,1).setRichTextValue(emailCell.build());
References:
newRichTextValue()
Class RichTextValueBuilder
Class RichTextValue

InDesign script searching for a word and printing page number(s)

I need an InDesign script that does the following:
Searching for a specific word in a specific paragraph style throughout the document
Printing the page number(s) to the console or as a .txt (I mean not the amount of pages, but the page number(s), i.e. p6, p11, p48 etc)
I am using CS6 and JS.
This should get you started:
app.findGrepPreferences=NothingEnum.NOTHING; //to reset the Grep search
app.findGrepPreferences.findWhat = 'Your text will be here'; //the word(s) you are searching
app.findGrepPreferences.appliedParagraphStyle = app.activeDocument.paragraphStyles.itemByName ("The name of your paragraph Style") //make sure it is spelled exactly as it is in the paragraph styles panel, including case
var fnd = app.activeDocument.findGrep (); //execute search
for (var i = 0; i < fnd.length; i++) { //loop through results and store the results
$.write (fnd [i].parentTextFrames[0].parentPage.name + '\n'); //output to console in Extendscript
}
One thing to know is that text frames outside the pages (on pasteboard) will cause this script to error so you need to try/catch it. But this is the general idea. Also this works in CC but in CS there was no 'parentPage' so this might need to be worked around.

Mail Merge Script not copying format

I'm trying to execute a mailmerge script that reads fields from a spreadsheet and the template from a google doc. The script runs on the google doc.
The script works fine except it doesn't copy the formatting or table that is in the document. This is crucial.
Below is the code I am using.
function mmerge() {
var mdoc=DocumentApp.getActiveDocument();
var mdat=SpreadsheetApp.openById("1Nc2xu--").getSheetByName("MailMerge List);
var numcols=mdat.getDataRange().getNumColumns();
var numrows=mdat.getDataRange().getNumRows();
var mtxt=mdoc.getBody().getText();
var flds=[];
for (var j=0;j<numcols;j++) {flds.push(mdat.getRange(1, j+1).getValue());}
var rtxt;
for (var i=2; i<=numrows; i++) {
rtxt=mtxt
for (var j=1; j<=numcols; j++) {
rtxt=rtxt.replace("{"+flds[j-1]+"}",mdat.getRange(i, j).getValue());
}
mdoc.getBody().appendParagraph(rtxt);
}
}
I suspect that it has to do with the method used here: mtxt=mdoc.getBody().getText() but I don't know how to change it. My attempts to change it to copy() results in an error.
Does anyone know what I am doing wrong? Any help would be greatly appreciated.
Update: This is not a straight forward copy problem: the process involves having to execute the mail merge and then apply the formatting to the mailmerged doc.
Thanks
getText() returns a String, which has no character formatting.
The greater issue is that G Suite Services in Google Apps Script does not provide the document as HTML. (The getAs() method on the Document object only allows you to retrieve it as a PDF.)
You can adapt the "Google Doc to clean HTML converter" script, although it won't be trivial. It currently does not convert table content into HTML tables, but that would be a great contribution to the script that you could make! The script is written in a very straight-forward way, so should be quite simple to modify.
Specifically, you'll need to check for ElementTypes related to tables (TABLE, TABLE_ROW, TABLE_CELL) and then wrap those elements in the appropriate HTML tags. You can see how oazabir did it in this example:
if (item.getType() == DocumentApp.ElementType.PARAGRAPH) {
switch (item.getHeading()) {
// Add a # for each heading level. No break, so we accumulate the right number.
case DocumentApp.ParagraphHeading.HEADING6:
prefix = "<h6>", suffix = "</h6>"; break;
case DocumentApp.ParagraphHeading.HEADING5:
prefix = "<h5>", suffix = "</h5>"; break;
case DocumentApp.ParagraphHeading.HEADING4:
prefix = "<h4>", suffix = "</h4>"; break;
case DocumentApp.ParagraphHeading.HEADING3:
prefix = "<h3>", suffix = "</h3>"; break;
case DocumentApp.ParagraphHeading.HEADING2:
prefix = "<h2>", suffix = "</h2>"; break;
case DocumentApp.ParagraphHeading.HEADING1:
prefix = "<h1>", suffix = "</h1>"; break;
default:
prefix = "<p>", suffix = "</p>";
}
if (item.getNumChildren() == 0)
return "";
}
Once you've converted your template into HTML, then you can manipulate it using your existing code. (For example, have ConvertGoogleDocToCleanHtml() return the HTML text and save that into your mtxt variable.)
Lastly, in your current script, you make multiple calls to get the same range. These calls are really slow. Instead, try to get the range once, get the values, and then operate on the returned Array.
var mailMergeRange = SpreadsheetApp.openById("1Nc2xu--").getSheetByName("MailMerge List").getDataRange().getValues();
var numcols = mailMergeRange.length;
var numrows = mailMergeRange[0].length;
You could also try this approach using Advanced Drive Services and the MailChimp API.

Need ExtendScript to open a file without knowing the full file name

New to ExtendScript and trying to finish an automation project for work.
I have a bunch of images that I am combining in photoshop via a script and need to open a image pairing based on an initial image. I know that the name of my paired file will be predictable up until the final character, at which point it will be any uppercase letter A-Z.
For example:
CH-14B1-SP-01-A can pairs with CH-14B1-SP-PV-01-A, but could also conceivably be paired with CH-14B1-SP-PV-01-B. Each paired file has an A-D replicate and we choose the best to be paired.
I have a script working that requires user input to decide what replicate to look for. I want to automate this. My code looks like this:
// ask user input for PV replicate letter
var repLetter =prompt("Which PV replicate would you like to use? (A.. B.. C.. etc.)");
// get the info out of the source doc
var fileName = srcDoc.name;
var docName = fileName.substring(0,fileName.length -4);
var filePath = srcDoc.path.toString();
var fileExt = fileName.substring(fileName.length -4, fileName.length);
var nameCheck = fileName.substring(0,fileName.indexOf("CH-14B1-SPI-"));
if (nameCheck <1)
{
var fileNum = fileName.substring(12,fileName.length -5) + repLetter;
// no underscore so we need to open it's namesake
// alert(nameCheck)
var filePair = filePath + "/PV/" + "CH-14B1-SPI-PV-" + fileNum + fileExt;
openThisFile(filePair)
Is there any way to make the var repLetter just accept any value at all?
Something like
var fileNum = fileName.substring(12,fileName.length -5) + [a-z];
I tried the above hoping it would do the trick (again very new to this) and I was told that "a" was undefined.
Your fault lies in the incorrect syntax in
var fileNum = fileName.substring(12,fileName.length -5) + [a-z];
... it's just bad syntax, you seem to be mixing GREP into JS. The error is issued because [...] indicates an array, which is valid to 'add' to a string, but the expression a-z ("a minus z") needs variables named a and z. I suppose you simply wanted some sort of wildcard here.
Circumvent the entire issue by reading a list of candidate files, based on the current file name. This is kind of hard to test locally because it requires lots of dummy files (and I'm not entirely sure I understand your procedure). However, the general idea of the following should be clear.
Rather than prompting for 'any' letter, it's more user friendly to show the available choices. I am not sure how you get the list of candidates, so I'll let you fill in that yourself. You need to adjust the getFiles call for this; currently, it reads the files from filePath, with a * after its name to pick up everything starting with nameCheck.
The found list of files is shown in a simple dialog with radio buttons to pick a file from. As it is, it only shows an alert, and if you press Cancel it does nothing.
Please note I have tested this inside InDesign, not Photoshop, as it's an easier test bed for scripts, and so it is possible some of the property names are off.
srcDoc = app.activeDocument;
var fileName = srcDoc.name;
var docName = fileName.substring(0,fileName.lastIndexOf('.'));
var filePath = srcDoc.filePath.toString();
var fileExt = fileName.substring(fileName.lastIndexOf('.')+1);
var nameCheck = fileName.substring(0,fileName.indexOf("CH-14B1-SPI-"));
var filelist = Folder(filePath).getFiles (nameCheck+'*.'+fileExt).sort();
if (filelist.length == 0)
{
alert ('No files found matching '+nameCheck+'*.'+fileExt);
} else
{
var fileDialog = app.dialogs.add({name:"Choose a file", canCancel:true});
with (fileDialog)
{
with(dialogColumns.add())
{
with (fileSel = radiobuttonGroups.add())
{
radiobuttonControls.add({staticLabel:filelist[i].name,checkedState:i==0});
}
}
}
if (fileDialog.show() == true)
{
alert ('you picked '+filelist[fileSel.selectedButton].name);
}
}

Incorporate variable into default tweet query string parameters

So I'm making a website that includes a simple javascript/HTML timer. The code for the timer is listed below.
I'm incorporating a tweet system into the website. My aim is for this tweet button to tweet "I lasted (timevariable)". I'm having trouble doing this as the twitter API seems to be kind of restrictive. The only way to configure default tweet text is through query string parameters. Is there any way to incorporate a variable (from the code below) into a query string parameter, or do I need to do this a more complicated way?
I have thought about doing the variable system with php but this code needs to be very lightweight in execution and because of that I would like to avoid php. Even if I did do it with php I would run into the same issue: how to incorporate a variable into a query string parameter that sets the default tweet.
TL;DR: How do I incorporate a variable into a query string parameter (in regards to twitters default tweet text API).
Here is a look at the way that twitter handles default tweet texts:
Tweet it
and here is the code for the counter that I am using.
<label id="minutes">00</label>:<label id="seconds">00</label>
<script type="text/javascript">
var minutesLabel = document.getElementById("minutes");
var secondsLabel = document.getElementById("seconds");
var totalSeconds = 0;
setInterval(setTime, 1000);
function setTime()
{
++totalSeconds;
secondsLabel.innerHTML = pad(totalSeconds%60);
minutesLabel.innerHTML = pad(parseInt(totalSeconds/60));
}
function pad(val)
{
var valString = val + "";
if(valString.length < 2)
{
return "0" + valString;
}
else
{
return valString;
}
}
</script>
Thank you
Here it is: http://jsfiddle.net/7zKAy/
As you'll see, I change the href of the link through javascript. Ignore the CSS and styles, it's just for show and better presentation.
Start by getting a reference to your link and setting up the base of the url you're going to be using:
var butt = document.getElementById('sharebutton');
var basehref = "https://twitter.com/share?text=";
Then, when you have text to send, build the complete URI. This is one way to do it:
// so i want to add "I lasted 345345334 seconds" to the text
basehref = "https://twitter.com/share?text=" + "\"" + encodeURIComponent("I lasted 345345334 seconds") + "\"";
Notice that I manually add the " at the ends of the string and only encode the contents with encodeURIComponent which is what you use if you want to encode part of a URI instead of all of it. If I was to do the entire thing at one, I'd do:
encodeURI(basehref);
then, attach this new href to your button:
butt.setAttribute('href', basehref);
and you're done. The link might be escaped by the browser when you mouse over it, so in the fiddle, check your console to see the actual string that gets applied to the href attribute.

Categories

Resources