Google Docs script, return text value in the middle of specified text - scripting

[current result][1]
[1]: https://i.stack.imgur.com/O8AGa.png
The problem is that they all apply to the same line
I want to get the values individually from the same line
Rule
▶random text◁
→ Change only values between ▶ and ◁
Script currently in use
var body = DocumentApp.getActiveDocument().getBody();
var foundElement = body.findText('▶([^\S]+)◁');
while (foundElement != null) {
// Get the text object from the element
var foundText = foundElement.getElement().asText();
// Where in the element is the found text?
var start = foundElement.getStartOffset();
var end = foundElement.getEndOffsetInclusive();
// Set Bold
foundText.setBold(start, end, true);
// Change the Foreground color
foundText.setForegroundColor(start, end, "#ff326d");
// Find the next match
foundElement = body.findText('▶([^\S]+)◁', foundElement);
}

Some regular expressions are not fully supported
As per the documentation A subset of the JavaScript regular expression features are not fully supported, such as capture groups and mode modifiers.
I'd recommend to open a feature request on Google Issue Tracker as recommended here

Related

Text Field with Standard PsiElement Auto Completion in IntelliJ Plugin

I'm trying to create a simple text field with auto completion for my IntelliJ plugin. I think this should be pretty simple but so far I've run into dead ends...
E.g. this should work as far as I understand:
EditorTextField format = new TextFieldWithCompletion(currentEditor.getProject(),
provider,
"",
true,
true,
true);
The problem is the provider. I'd expect to see a provider that isn't a list provider. I just want to show the completion matching the current line in the editor cursor so I'd like the full completion dialog and not just a short list of options.
I also looked at TextFieldWithAutoCompletion but it seems to be designed for hardcoded string values instead of free form completion.
I just want the standard Java/Kotlin completion. Not a custom list or anything like that. I saw some discussion with replacing the document of the text field but I couldn't get that to work either. I have a PsiExpressionCodeFragment and would expect there to be a completion provider that accepts that but I can't find it.
For reference what I want to do is something very similar to the conditional statement in the breakpoint dialog.
Another approach illustrated here is:
JavaCodeFragmentFactory jcff = JavaCodeFragmentFactory.getInstance(currentEditor.getProject());
PsiFile pf = PsiDocumentManager.getInstance(currentEditor.getProject()).getPsiFile(currentEditor.getDocument());
PsiElement psiElement = pf.findElementAt(currentEditor.getCaretModel().getOffset());
PsiExpressionCodeFragment fragment = jcff.createExpressionCodeFragment("", psiElement,null, false);
EditorTextField f = new EditorTextField(PsiDocumentManager.getInstance(currentEditor.getProject()).getDocument(fragment),
currentEditor.getProject(),
FileTypes.PLAIN_TEXT, false, true);
This loads the UI but doesn't popup code completion no matter what I type.
The trick is to create an editor that contains an instance of the Document. And this document refers to a language and a psi element context:
JPanel panel = new JPanel();
// Just detect an element under caret for context
PsiFile psiFile = PsiDocumentManager.getInstance(editor.getProject()).getPsiFile(editor.getDocument());
PsiElement element = psiFile.findElementAt(editor.getCaretModel().getOffset());
PsiExpressionCodeFragment code = JavaCodeFragmentFactory.getInstance(editor.getProject()).createExpressionCodeFragment("", element, null, true);
Document document = PsiDocumentManager.getInstance(editor.getProject()).getDocument(code);
EditorTextField myInput = new EditorTextField(document, editor.getProject(), JavaFileType.INSTANCE);
myInput.setPreferredWidth(300);
panel.add(myInput);
return panel;
Here the caret used to be located on dsa5, so the dsa5 variable is not yet visible for the completion.

Remove "MIME type" column from Filent Content List

I am Using a Script Adapter by passing payload to get contend for a Content List from "Search with values" event
When Contend get loaded to content list , i have a custom view to preview them. But if i clicked on MIME type column , It opens a separate view with the mapped viewer
So I need to remove this column or make it un-clickable
1) I am passing search values to content list's "Search with values" event , from where can i handle Content List's contend loading ,any Dojo Event i can use ?
2) With Script Adapter can i do this without going for a "response filter"
Edit :
As Nicely explained by "Ivo Jonker" (in his answer - "or try to specifically locate the widgets on your page" and with his example code)
responsed = page.ContentList8.ecmContentList.getResultSet();
var cols = responsed.structure.cells[0];
for (i=cols.length-1; i>0; i--){
var col = cols[i];
if (col.field=="mimeTypeIcon")
cols.splice(i,1);
}
page.ContentList78.ecmContentList.setResultSet(responsed);
I simply remove this row. Thanks Again and lovely blog , hope you keep posting more great articles.
The values passed through the Search With Values event will eventually be handled by the icm.pgwidget.contentlist.dijit.DocumentSearchHandler
that in turn creates a SearchTemplate to execute the search (ecm.model.SearchTemplate.prototype.search). One option would be to aspect/before/around the DocumentSearchHandler#query to manipulat the searchresults and by that way to remove the column.
The wiring however does not provide any handles to achieve this for a specific query-resultset combination leaving you to either fix this on a global scale (icm.pgwidget.contentlist.dijit.DocumentSearchHandler.prototype#query), or try to specifically locate the widgets on your page.
Personally, taking into account #2, i'd go for the responsefilter-option if you feel the global solution wouldn't be a problem, or alternatively i'd personally prefer to create a simple ICM widget that instantiates/implements a "plain" ecm.widget.listView.ContentList and exposes a wire to set the ecm.model.Resultset.
You'd then be able to create your own Searchquery in a scriptadapter, remove the column, and pass the resultset.
The script adapter could be something like:
var scriptadapter=this;
var queryParams={};
queryParams.query = "SELECT * FROM Document where id in /*your list*/";
queryParams.retrieveAllVersions = false;
queryParams.retrieveLatestVersion = true;
queryParams.repository = ecm.model.desktop.repositories[0];
queryParams.resultsDisplay = {
"sortBy": "{NAME}",
"sortAsc": true,
"columns": ["{NAME}"],
"honorNameProperty": true};
var searchQuery = new ecm.model.SearchQuery(queryParams);
searchQuery.search(function(response/*ecm.model.Resultset*/){
//remove the mimeTypeIcon
var cols = response.structure.cells[0];
for (i=cols.length-1; i>0; i--){
var col = cols[i];
if (col.field=="mimeTypeIcon")
cols.splice(i,1);
}
//emit the resultset to your new contentlist, be sure to block the regular synchrounous output of the scriptadapter
scriptadapter.onPublishEvent("icm.SendEventPayload",response);
//The contentlist wire would simply do contentlist.setResultSet(response);
});

Illustrator variables - dynamically line up two text strings next to each other when autogenerating

I am automating the generation of several thousand labels in Adobe Illustrator. The use of the VariableImporter script has made easy work of it so far, but now I have reached an issue where I am stumped. The original plan worked great, until the powers that be requested that one line of text have a bold text string, followed by a normal weight text string. Before, when the font weights were the same I could have connected the two strings of text in the CSV file prior to loading them into the drawing, and they would have came out lying right next to each other. This is now no longer possible and I can't think of a solution that is not incredibly fussy.
I don't know illustrator very well, so I am thinking I could just be unaware of some setting that would stick an object next to another one even as the other one moves.
Okay here is the way I figured out how to do this with help from Adobe forums and from Vasily.
First of all, use InDesign if possible. It is better at performing a Data Merge and can do this without your scripting.
Write out <variable1> <variable2> which is formatted as needed on the same line of text.
You will need to have the variables that you are putting in there somewhere in the illustration. Recommended to put it in a hidden layer behind everything.
replace variable1 and variable2 with the names of your variables where the functions getVariableContents() are called in this script
var idoc = app.activeDocument;
var vars = idoc.variables;
var replace1 = /<variable1>/g;
var replace2 = /<variable2>/g;
// author CarlosCanto on adobe forums
function getVariableContents(variableName) {
var idoc = app.activeDocument;
var ivar = idoc.variables.getByName(variableName);
return ivar.pageItems[0].contents;
}
var replaceWith1 = getVariableContents('variable1'), result;
var replaceWith2 = getVariableContents('variable2'), result;
// regex_changeContentsOfWordOrString_RemainFormatting.jsx
// regards pixxxel schubser
function exchangeWords(s, replacer) {
var s = s;
var replacer = replacer;
var atfs = activeDocument.textFrames;
for (var i = atfs.length - 1; i >= 0; i--) {
atf = atfs[i];
while (result = s.exec(atf.contents)) {
try {
aCon = atf.characters[result.index];
aCon.length = result[0].length;
aCon.contents = aCon.contents.replace(s, replacer);
} catch (e) {};
}
}
}
exchangeWords(replace1,replaceWith1);
exchangeWords(replace2,replaceWith2);
run the script
There is a way to accomplish this by having a script do some processing during the course of your batch output, and an organizational system which adds some overhead to your file, in terms of adding more text boxes and possibly an extra layer to your document. But - here's what you can have: a hidden layer with all your variables there in separate single point-text objects, and a layer with your regular template objects such as any point text or area-text objects. Your art text objects will need to be re-worked to contain a string with multiple variable placeholders like this: "Hello, <FirstName> <LastName>". The placeholders can be styled, and a processing script would then need to replace the <placeholder> words with your real variable values. Where are the varible values? They are going to be populating into your hidden layer which has your separate text objects and the script would need to read the contents of each of those to put into the <placeholders>. ~~Those same text fields can be styled as you wish, and the script could apply the same styles to your text when it is replaced in the main text body.~~ -actually this won't be necessary of your routine backs up the original text frame with the placeholder in it, therefore preserving the styling, but it may be necessary if you are going to instead use an external text file to keep your original text in. And of course, it will need to make a backup of the original text with all the <placeholders> so that it will reset the text for every new dataset during your batch process.
However, this is much easier done in Indesign, can you not use ID for your task?
I modified script from #tucker-david-grebitus's answer. So now it gets all textual variables and replaces all their names edged by percent symbol
for (var i = activeDocument.variables.length - 1; i >= 0; i -= 1) {
var variable = activeDocument.variables[i];
if (variable.kind !== VariableKind.TEXTUAL || !variable.pageItems.length) {
continue;
}
var search = new RegExp('%' + variable.name + '%', 'g');
var value = variable.pageItems[0].contents;
for (var j = activeDocument.textFrames.length - 1; j >= 0; j -= 1) {
var textFrame = activeDocument.textFrames[j];
textFrame.contents = textFrame.contents.replace(search, value);
}
}

How to check multiple PDF files for annotations/comments?

Problem: I routinely receive PDF reports and annotate (highlight etc.) some of them. I had the bad habit of saving the annotated PDFs together with the non-annotated PDFs. I now have hundreds of PDF files in the same folder, some annotated and some not. Is there a way to check every PDF file for annotations and copy only the annotated ones to a new folder?
Thanks a lot!
I'm on Win 7 64bit, I have Adobe Acrobat XI installed and I'm able to do some beginner coding in Python and Javascript
Please ignore the following suggestion, since the answers already solved the problem.
EDIT: Following Mr. Wyss' suggestion, I created the following code for Acrobat's Javascript console to be run only once at the beginning:
counter = 1;
// Open a new report
var rep = new Report();
rep.size = 1.2;
rep.color = color.blue;
rep.writeText("Files WITH Annotations");
Then this code should be applied to all PDFs:
this.syncAnnotScan();
annots = this.getAnnots();
path = this.path;
if (annots) {
rep.color = color.black;
rep.writeText(" ");
rep.writeText(counter.toString()+"- "+path);
rep.writeText(" ");
if (counter% 20 == 0) {
rep.breakPage();
}
counter++;
}
And, at last, one code to be run only once at the end:
//Now open the report
var docRep = rep.open("files_with_annots.pdf");
There are two problems with this solution:
1. The "Action Wizard" seems to always apply the same code afresh to each PDF (that means that the "counter" variable, for instance, is meaningless; it will always be = 1. But more importantly, var "rep" will be unassigned when the middle code is run on different PDFs).
2. How can I make the codes that should be run only once run only at the beginning or at the end, instead of running everytime for every single PDF (like it does by default)?
Thank you very much again for your help!
This would be possible using the Action Wizard to put together an action.
The function to determine whether there are annotations in the document would be done in Acrobat JavaScript. Roughly, the core function would look like this:
this.syncAnnotScan() ; // updates all annots
var myAnnots = this.getAnnots() ;
if (myAnnots != null) {
// do something if there are annots
} else {
// do something if there are no annots
}
And that should get you there.
I am not completely positive, but I think there is also a Preflight check which tells you whether there are annotations in the document. If so, you would create a Preflight droplet, which would sort out the annotated and not annotated documents.
Mr. Wyss is right, here's a step-by-step guide:
In Acrobat XI Pro, go to the 'Tools' panel on the right side
Click on the 'Action Wizard' tab (you must first make it visible, though)
Click on 'Create New Action...', choose 'More tools' > 'Execute Javascript' and add it to right-hand pane > click on 'Execute Javascript' > 'Specify Settings' (uncheck 'prompt user' if you want) > paste this code:
.
this.syncAnnotScan();
var annots = this.getAnnots();
var fname = this.documentFileName;
fname = fname.replace(",", ";");
var errormsg = "";
if (annots) {
try {
this.saveAs({
cPath: "/c/folder/"+fname,
bPromptToOverwrite: false //make this 'true' if you want to be prompted on overwrites
});
} catch(e) {
for (var i in e)
{errormsg+= (i + ": " + e[i]+ " / ");}
app.alert({
cMsg: "Error! Unable to save the file under this name ('"+fname+"'- possibly an unicode string?) See this: "+errormsg,
cTitle: "Damn you Acrobat"
});
}
;}
annots = 0;
Save and run it! All your annotated PDFs will be saved to 'c:\folder' (but only if this folder already exists!)
Be sure to enable first Javascript in 'Edit' > 'Preferences...' > 'Javascript' > 'Enable Acrobat Javascript'.
VERY IMPORTANT: Acrobat's JS has a bug that doesn't allow Docs to be saved with commas (",") in their names (e.g., "Meeting with suppliers, May 11th.pdf" - this will get an error). Therefore, I substitute in the code above all "," for ";".

How to trigger specific Google Custom Search Engine refinement label?

Currently, our organization is using Google Custom Search engine to provide auto suggestion, and we have about 3 refinement labels configured in our CSE. Previously, we're using WebSearch and SearchControl, and the WebSearch has a setSiteRestriction method which allows us to specifically select a refinement label:
- http://code.google.com/apis/websearch/docs/reference.html#_class_GwebSearch
Previous code example:
var searchControl = new google.search.SearchControl();
var webSearch = new google.search.WebSearch();
//Refinement allows us to tell Google which specific sites to search
var refinement="Support";
//filter custom search and currently there are 3 refinements
(some other variables declaration here including 'product')
switch(product)
{
case "10000":
refinement = "Support1";
break;
case "10200":
refinement = "Support1";
break;
case "10001":
refinement = "Support2";
break;
default:
break;
}
/*this is the code to fill in the custom search. The refinement was set above - either "Support", "Support1", or "Support2".*/
webSearch.setSiteRestriction('cseId', refinement);
......
However, currently we're migrating to CustomSearchControl tool to replace the deprecated WebSearch, but apparently I couldn't find any way to specifically select a refinement label based on the value of switch case statement. Immediate help needed here, and if there's a relevant docs that you guys can point me to will be much appreciated. thanks! :)
When using customSearchControl, you can set the refinement label in the options.
This will
a) not restrict other refinements in your search to the keywords you
may have added with ('more: ' + refinement), and
b) also highlight
the refinement tab to tell the user what you did on their behalf.
var customSearchOptions =
{ 'defaultToRefinement' : 'refinement_label_name' };
var customSearchControl =
new google.search.CustomSearchControl('YOUR_CSE_ID', customSearchOptions);
The defaultToRefinement parameter is mentioned in the Custom Search Element JavaScript API Reference.
Previously, this answer was introduced here.
Got the answer. Appended the following lines to the code:
var customSearchControl = new google.search.CustomSearchControl(cseId);
customSearchControl.setSearchStartingCallback(this, function(control, searcher, query)
{
searcher.setQueryAddition('more:' + refinement);
});