I have written this code for a tampermonkey, got TM to execute the code using mutation observers, but nothing is changing on the page. the goal is to turn text that passes the regex into a link to a site to lookup that value.
async function addeelinks(jnode) {
/* regular expression to find all ee */
const regex = new RegExp("^S[a-zA-Z0-9]{9}_001_v$")
/* gets an array of all html elements where ee are known to hang out*/
var cells = document.getElementsByTagName('td');
/* steps through all the items in the array looking at each one individually */
for (var i = 1; 1 > cells.length; i++) {
/* grabs the contents of the td */
var cellvalue = cells[i].firstChild.data;
/* if the contents look like a ee then... */
if (regex.test(cellvalue)){
/* wrap the ee in a link to site for the ee */
cells[i].firstChild.data = "'<a href='https://example.com/search?value='" + cellvalue + "' target='example' >'" + cellvalue + "'</a>'";
}
}
}
I tried validating my regex with example data, and its solid. I tried swapping firstChild.data with .innerHTML based on some other question/answers I found on stack exchange, and even found suggestions to use .replace, but hitting a brick wall here. I'm not very familiar with javascript so I assume I'm making a very basic error.
Related
I use Extendscript to help me review students' work in InDesign. I run a script that goes through a document and creates a report. One of the things I need to list on that report is wether or nor unused paragraph styles exist, preferably also listing their names.
I tried:
Searching the documentation for a property that might indicate if the
paragraph style is being used or not.
Invoking (.invoke() method) the Select All Unused action from the
Paragraph Styles panel. I explored adding event listeners and looking for any results, and also exploring the Panel documentation to check for a selection. According to an older topic here - InDesign scripting, get the items selected in a panel -, this is not possible.
I also considered looping through all stories and paragraphs, checking for the styles in use, and accounting for styles used inside other styles. However, I feel there should be a simpler alternative.
EDIT: The point is to avoid manual, tedious and error-prone work for about 5 exercises x 60 students per semester. The report already includes many other things, like page size, bleed, margins, parent page columns and application, text style options, baseline grid, etc. This script saves me a HUGE amount of time and makes it less likely that I'll forget to check for anything in particular. That's why I'm trying to integrate as many features as possible into it, so the individual manual work is reduced to the absolute minimum.
After choosing "Select All Unused" from the Paragraph Styles panel, you should be able to click the trash can icon to delete those styles. The same should work for the Character Styles panel.
I wondered if ChatGPT was smart enough to figure this out. It helped, but couldn't deliver a full solution. We went through 10 different versions before getting close to the working version of the script below.
Here's my final version:
var myDocument = app.activeDocument;
// Get all the character styles in the document
var allCharacterStyles = myDocument.allCharacterStyles;
// Loop through each character style
for (var i = 0; i < allCharacterStyles.length; i++) {
var style = allCharacterStyles[i];
// Set the search criteria for the findText() method
app.findTextPreferences = NothingEnum.nothing;
app.findTextPreferences.appliedCharacterStyle = style;
// Search entire document for instances of the character style
var found = myDocument.findText();
// If the style is not found in the document, delete it
if (found.length == 0) {
try {
style.remove();
} catch (e) {
// Ignore the error
}
}
// Reset the findTextPreferences object
app.findTextPreferences = NothingEnum.nothing;
}
// Repeat the above for Paragraph Styles
// Get all the paragraph styles in the document
var allParagraphStyles = myDocument.allParagraphStyles;
// Loop through each paragraph style
for (var i = 0; i < allParagraphStyles.length; i++) {
var style = allParagraphStyles[i];
// Set the search criteria for the findText() method
app.findTextPreferences = NothingEnum.nothing;
app.findTextPreferences.appliedParagraphStyle = style;
// Search entire document for instances of the style
var found = myDocument.findText();
// If the style is not found in the document, delete it
if (found.length == 0) {
try {
style.remove();
} catch (e) {
// Ignore the errors
}
}
// Reset the findTextPreferences object
app.findTextPreferences = NothingEnum.nothing;
}
And here's a version that generates a report showing a list of unused paragraph styles. Again, ChatGPT can help with some, but it couldn't produce a final version. My edited and tested script appears below.
var myDocument = app.activeDocument;
// Create an array to store the names of unused styles
var unusedStyles = [];
// Get all the paragraph styles in the document
var allParagraphStyles = myDocument.allParagraphStyles;
// Loop through each paragraph style
for (var i = 0; i < allParagraphStyles.length; i++) {
var style = allParagraphStyles[i];
// Set the search criteria for the findText() method
app.findTextPreferences = NothingEnum.nothing;
app.findTextPreferences.appliedParagraphStyle = style;
// Search for instances of the style in the document
var found = myDocument.findText();
// If the style is not found in the document, add it to the list of unused styles
if (found.length == 0) {
unusedStyles.push("Paragraph style: " + style.name);
}
// Reset the findTextPreferences object
app.findTextPreferences = NothingEnum.nothing;
}
// Create a new text frame to hold the report text
var textFrame = myDocument.pages[0].textFrames.add();
textFrame.geometricBounds = [3, 18, 36, 3];
// Insert the list of unused styles into the text frame
for (var i = 0; i < unusedStyles.length; i++) {
textFrame.contents += unusedStyles[i] + "\n";
}
I am new to JavaScript and even newer to InDesign. Could you please help me on this problem ?
I need to extract the text of 3 cells of a tab. Those 3 cells each have a dedicated paragraphstyle : print.rv, print.qty, print.ref.
The tab is of that form on my page (in a textframe):
Ref
ref_number (paragraphstyle: print.ref)
Quantity
qty_number (paragraphstyle : print.qty)
Recto/Verso
recto_verso or not (paragraphstyle : print.rv)
So i need to extract separately each string of the 2nd column. (The final objective is to write those string in the name of the exported pdf version of the project).
Thanks for your help :-) !
Input:
Code:
var doc = app.activeDocument
// convert all tables into the text
doc.stories.everyItem().tables.everyItem().convertToText("\t", "\r");
// for every line in the text: remove all characters from the start up to the tab symbol
app.findGrepPreferences.findWhat = "^.+\t";
app.changeGrepPreferences.changeTo = "";
doc.changeGrep();
// get all paragraphs from first text frame
var pgfs = doc.textFrames[0].paragraphs.everyItem().getElements();
// your styles (they can be obtained automatically)
var styles = ["rv", "qty", "ref"];
// 2D-array with paragraphs grouped by style
var pgf_groups = [];
// fill the array with paragraphs
for (var s=0; s<styles.length; s++) {
var style_group = [] // array for every style
for (var i=0; i<pgfs.length; i++) {
if (pgfs[i].appliedParagraphStyle.name == styles[s])
style_group.push(pgfs[i]);
}
pgf_groups.push(style_group); // push the array into 2D-array
}
// output (get contents from the 2D-array and join it in a readable string)
function get_text(pgfs) {
var txt = "";
for (var i=0; i<pgfs.length; i++) txt = txt + pgfs[i].contents + "\n";
return txt;
}
msg = ""
+ styles[0] + ":\n" + get_text(pgf_groups[0]) + "\n\n"
+ styles[1] + ":\n" + get_text(pgf_groups[1]) + "\n\n"
+ styles[2] + ":\n" + get_text(pgf_groups[2]);
alert(msg);
Output:
Sorry, I don't get what do you mean 'to write those string in the name of the exported pdf version of the project'.
Actually the implementation heavily depends on many details. Does your document contain another text beside the table? (I supposed your document contain just the table and nothing else). In case if there is another text, will you select the table manually? Does the table always have 3 row? (I supposed there can be many rows) How exactly you will open the document? How you will run the script? Etc...
Probably for simplest case it would be enough the first five lines of the script: convert the table into text and get rid of characters before tab symbols.
Thanks Yuri for your answer ! First your code is running but it doesn't return any value. I don't understand why haha. I think the issue is line 12 as I don't have an only text box I don't select the good paragraph styles but I don't know how to get every paragraphs styles of the page :/.
Moreover as you said, I should have been more precise on my post.
I work on files which are composed of multiple pages, those pages all have multiple text boxes but they all have one in common attached to the template. It is from this text box that I want to extract the data, it contains the table I presented in the original post. The script will be executed directly from InDesign.
Then I must export individually each page in a PDF and write the informations I got from the table in the title of each file.
For example if my file is called test.indd and my first page has ref_number: 05, qty_number: 3 and is a recto i should export the first page as a pdf called test_05_3_recto.pdf.
Thanks for your help and thanks for your time !
Having a lot of trouble finding this and as a very beginner programmer, I can't quite troubleshoot my way through this.
What I want to do:
Automatically log the word count of a google doc in a google sheets cell.
The code I've been playing with to try and make it happen that is probably super wrong:
function countWords() {
var doc = DocumentApp.openByURL().getBody().getText();
var punctuationless = doc.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()"?“”]/g," ");
var finalString = punctuationless.replace(/\s{2,}/g," ");
var count = finalString.trim().split(/\s+/).length;
return count;
Ideally, what I'd like to do is, in sheets, set it up so there's a column with links to google docs and be able to just put in a function that will return the wordcount from that doc.
Answer:
You can not create a custom function to do this, as reading another document requires authentication. You can however do this with an in-sheet button which runs the script.
More Information:
As per the documentation on custom functions, it is not possible to run methods which require authentication such as DocumentApp:
Unlike most other types of Apps Scripts, custom functions never ask users to authorize access to personal data. Consequently, they can only call services that do not have access to personal data
As a result, you will instead have to manually run the script - but this can be done from a button in the Sheet.
Code:
Assuming that you have the Document links in column A and wish for the word count to be in column B (starting in row 2):
function countWords() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var linkRange = ss.getRange("A2:A");
try {
linkRange.getValues().forEach(function(cell, index) {
if (cell[0] == "") {
throw "Cell A" + (index + 2) + " is empty"
}
let doc = DocumentApp.openByUrl(cell[0]).getBody().getText();
let count = (doc.match(/\b\S+\b/g) || []).length;
ss.getRange(index + 2, 2).setValue(count);
});
}
catch (err) {
console.log(err);
return;
}
}
Rundown of this function:
Open the sheet containing the document links (remember to change the sheet name!)
Get the range of links down column A
Loop through each link and obtain the Document's text
Obtain all instances of word-boundary/non-whitespace/word-boundary in the document, puts them all into an array, and gets the length of the array.
In this step, if the document is empty, then an empty array is given
Sets the cell in column B adjacent to the link to the result of the count.
This is all wrapped inside a try/catch so that the script stops execution when it reaches an empty cell in column A.
Assigning to a Button:
Now, you can create an in-sheet button which will run the script whenever you click it.
Go to the Insert > Drawing menu item and create a shape; any shape will do, this will act as your button.
Press Save and Close to add this to your sheet.
Move the newly-added drawing to where you would like. In the top-right of the drawing, you will see the vertical ellipsis menu (⋮). Click this, and then click Assign script.
In the new window, type countWords and press OK.
Now, each time you click the button, the script will run.
Visual Example:
References:
Custom Functions in Google Sheets | Apps Script | Google Developers
Okay so I'm here trying to get myself acquainted with Adobe Acrobat's Javascript API -- I feel like I may be missing some easy ways of doing certain things, but let's find that out together.
The Question:
How would I go about finding the amount of pages that belong to a bookmark?
For example, I have the following Bookmark layout:
Intro [3 pages]
Factions [2 pages]
Character [3 pages]
End [1 page]
(would have posted a picture, but I don't have the permission to do so :/)
Essentially I would like to be able to automate the extraction of the # of pages each bookmark has, for a little project I'm working on to speed stuff up at work.
My code thus far:
/* Count Bookmark Children
TODO: Count Pages of each Bookmark */
function CountBm(bm) {
var count = 0;
console.println("Bookmark name: " + bm.name);
bm.execute(); // goto bm -- not necessary, just for personal reasons
console.println("Bookmark Start Page: " + (this.pageNum+1));
/* This would only work if each page in the bookmark was a child
of the bookmark being checked */
if (bm.children != null) {
for (var i = 0; i < bm.children.length; i++)
count++;
}
console.println("Pages in Bookmark: " + count);
}
var bkmk = bookmarkRoot.children[2]; // Character Bookmark
CountBm(bkmk);
Also, for the last two lines of that code, is there a better way to reference specific bookmarks? By name, perhaps?
I have done this by using the current bookmark's execute() destination relative to the next bookmark's execute() destination. So assuming the bookmarks follow the flow of the document, just run execute() on the next bookmark, and use this.pageNum to figure out how many pages you have jumped forward.
Something like:
this.pageNum = 0;
for (var i = 1; i < this.bookmarkRoot.children.length; i++) {
page = this.pageNum;
this.bookmarkRoot.children[i].execute();
console.println("This bookmark is " + (this.pageNum-page) + " pages long");
}
You can add handling for grandchildren bookmarks as well, depending on your application. The right solution is dependent upon the structure of your bookmarks. The print to console line above could be replaced with this.extractPages(...) for your application.
Unfortunately that's the only way to reference bookmarks. If you wanted to find a bookmark by it's name, you could store all the bookmark names in an object with their child indexes. It's a hack, but it can be helpful when you have a document with a large number of bookmarks.
i'm creating a new dom element:
var bubbleDOM = document.createElement('div');
bubbleDOM.setAttribute('class', 'selection_bubble');
document.body.appendChild(bubbleDOM);
then i populate data to this DOM in a manner of text using .responseText with
XMLHttpRequest and finally change it's css:
.selection_bubble {
position: absolute;
}
Everything works great until now. my problem is that a part of the data i've populated to
the DOM element has a href link such as:
/prop.php?id=333
which makes them think the link is really coming from my website, so when the user clicks on it he goes to:
http://www.mywebsite.com/prop.php?id=333
and i want those links to appear from the website (which i know it's name and there is
only one i'm pulling the data from) as they should be:
http://www.thesitei'mpullingfrom.com/prop.php?id=333
How can i change this either with CSS or JS?
To improve my original comment on the question:
In order to fix only the URLs that start with a slash (/), something like the following command should be run:
(edited in accordance with the comment fixing the expression)
responseText.replace(/(href=")(\/[^"]+)"/g, "$1http://thesiteimpullingfrom.com$2\"")
Parse the (X)HTML into a DOM Object then get all the anchor Elements and replace their href attributes. E.g.:
var i = 0, n ;
var l ;
var s ;
l = dom.getElementsByTagName("a") ;
for( n = l.length; i < n ; i++ ) {
o = l[i] ;
if( !! ( s = o.getAttribute("href") ) ) {
// add domain to s
o.setAttribute("href") ;
}
}