Situation:
I have made my self a speadsheet to enter my working times. For some cases I have to enter some links and name them with part of the linkname. So I decided to create a custom menu where I simply post the link in a prompt and the script cuts out needed name and enters this to my sheet.
Now this is only running in my sheet. Guess there is no need to publish something like this :)
To my problem:
I have a main workingsheet and copy this every week because one sheet only solves one week. My script causes me to grant permissions to it so it can do upper described actions on current sheet. But everytime I copy the sheet (so every week) I have to grand the permissions again. Looking to my google account seeing granted permissions giving me headache since there are planty of entries for granting permissions :(
Question:
Is there a way to stay in kind of a developermode to prevent this permission requests?
Why do I have to grand permissions to my own script?
function onOpen(e) {
var menu = SpreadsheetApp.getUi().createMenu('Custom Menu');
menu.addItem('Add Ticket', 'addTicket');
menu.addItem('Rename to KW XX', 'renameDocument');
menu.addToUi();
}
function addTicket() {
var ui = SpreadsheetApp.getUi(); // Same variations.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var myCell = sheet.getActiveCell();
var result = ui.prompt(
'Add Ticket',
'Please enter Ticket-link:',
ui.ButtonSet.OK_CANCEL);
// Process the user's response.
var button = result.getSelectedButton();
var link = result.getResponseText();
if (button == ui.Button.OK) {
var n = link.lastIndexOf('/');
var linkName = link.substring(n+1);
var vals = myCell.setValue('=HYPERLINK("' + link + '";"' + linkName + '")');
} else if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert('You cancled adding ticket.');
} else if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert('You closed the dialog. No ticket was inserted.');
}
}
function renameDocument() {
eval(UrlFetchApp.fetch('https://momentjs.com/downloads/moment-with-locales.js').getContentText());
var sheet = SpreadsheetApp.getActive();
var doc = DocumentApp.getActiveDocument();
moment.locale('de');
var kw = moment().format('ww');
var name = sheet.getName();
sheet.setName('KW ' + kw);
}
I understand that by "sheet" you mean spreadsheet, a.k.a. workbook, document and file, because using a script on several sheets that are on the same spreadsheet doesn't require to authorize the script for each one and because you are seeing a "plenty of entries for granting permissions"
Also I understand that your script is on a script project bounded to an spreadsheet.
When we make a copy of an spreadsheet it will contain a copy to the script project bounded to it. The new spreadsheet and its bounded project as they are different files and the policy of Google is that the authorization to run a script is given by script project.
The way to avoid having a lot of copies of the same code code and have to authorize each of them is to use an add-on, that is the reason that I vote to close this question as duplicate of Use script in all spreadsheets
Anyway the answer to
Is there a way to stay in kind of a developermode to prevent this permission requests?
is develop an add-on.
and to
Why do I have to grand permissions to my own script?
Because you are not being asked to grant permissions to one script you are being asked to grant permission to each copy.
It's worth to note that besides the headache of having to grant permissions to each copy, if you made a change to "your script" it will be only on the script project where you write it, that change will not be "propagated" to the copies.
An alternative is to use a library but you still will have to grant permissions to each script project where you use the library.
Regarding the developer fee to publish on the Google Chrome Web Store, you could run your add-on on test mode but you will have to add each file to the corresponding list which is not very friendly to handle a large list of files.
Related
I'm using dhee.ai widgets to take orders on my site. I've identified cases where I want to programattically launch the widget with certain user intents upfront. This should happen without user having to click on the bot icon.
How can I do that ?
It can be done using a javascript call as below
var myIntent = 'yourIntentToBeServedOnStartup'
var myParams = {param1:value1} //optional
var phoneNum = '9999999999'
DheeChatWidget.launchWithIntent("Guest", phoneNum, language, myIntent, myParams);
An example HTML which uses a custom intent to launch, can be seen here
https://github.com/DheeYantra/dhee-widget-examples/blob/main/src/main/resources/static/index.html
I have several sheets that begin with "Agent Report" followed by the name, like this: "Agent Report - John", "Agent Report - Adam", etc. I have a script that reads the name of the agent from a specific cell and retrieves the data from another spreadsheet for that person. I want to trigger the script when a sheet that begins with "Agent Report" is activated, so that when I move between the sheets, the sheet data are updated for each person in "Agent Report" sheets. So far I have this:
function onOpen(e) {
makeMenu();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sname = ss.getActiveSheet().getName();
if(sname.indexOf("Agent Report")>-1){
master();
}
}
Agent Report is not the first sheet, so the script correctly makes a custom menu (makeMenu) when I open the spreadsheet, but does not get triggered (master) when I switch to an "Agent Report" sheet. When I run the script manually from an "Agent Report" sheet, it runs fine.
My question is: Can I create a trigger that will run the script when I switch to a sheet with the name that begins with "Agent Report"? onOpen() doesn't seem to fit for that purpose.
If such a trigger is not possible, can there be a workaround - a loop that would go over every sheet, check the name and if it contains "Agent Report", run the script. Something like that:
function onOpen(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var numberOfSheets = ss.getSheets().length;
for (var i = 0; i<=numberOfSheets; i ++) {
if(SOMETHING HERE.indexOf("Agent Report")[i] > -1){
master();
}
}
}
Issue:
According to the official documentation:
The onOpen(e) trigger runs automatically when a user opens a
spreadsheet, document, presentation, or form that they have permission
to edit.
The problem with this approach is that onOpen is executed only the time you open the spreadsheet file. Therefore, even if you switch between sheets or do any other operations, the script won't be executed, unless you refresh/open the spreadsheet file again. In other words, onOpen will only be executed for the sheet that you open the first time.
Solution 1:
To execute a code when switching between different sheets you can use onSelectionChange(e):
function onSelectionChange(e) {
makeMenu();
const as = e.source.getActiveSheet();
if (as.getName().indexOf("Agent Report")>-1){
master();
}
}
I don't recommend you to choose this approach because every time you make a selection change in the script, the code will be executed.
Solution 2 (recommended):
As you also proposed, to control when you want to execute the script I would advice you to use a regular function that iterates over all sheets and checks if the sheet name matches the criterion. Add also onOpen to execute makeMenu():
function allSheets(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
sheets.forEach(sh=>{
if(sh.getName().indexOf("Agent Report")>-1){
master();
}});
}
function onOpen() {
makeMenu();
}
You can execute this regular function in many different ways:
script editor
create a custom menu and execute it from the spreadsheet file
create an icon button within your spreadsheet file
create a time-driven trigger to execute on a particular time
Bonus information:
In both approaches, you can replace
if(as.getName().indexOf("Agent Report")>-1)
with
if(as.getName().includes("Agent Report"))
which does exactly the same thing, but it is more eye-friendly.
Related Issue:
As also pointed out by Iamblichus, an onSheetChange trigger function has already been requested by the community and it is reported in the IssueTracker. Go ahead and click on the star (★) button to the top left of the webpage to increase the chances of this feature to be implemented in the future.
The final solution was to use installable trigger (not a simple trigger, this is why the script did not run onOpen) with the following script:
function allSheets() {
makeMenu();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
sheets.forEach(sh=>{
SpreadsheetApp.setActiveSheet(sh);
if (sh.getName().includes("Agent Report")) {
master();
}
})
SpreadsheetApp.setActiveSheet(sheets[0]);
}
Thank you #Marios for all the helpful tips.
I have a simple function that creates a folder on google drive. I want to transfer the name to it and run it from the Sheets. But I'm denied access. How to solve this problem without triggers? Thank you
function myFunction() {
var folderName = "SEO";
var folder=DriveApp.getFoldersByName(folderName).next();
var fileName = "NewFolder";
var file=SpreadsheetApp.create(fileName);
var copyFile=DriveApp.getFileById(file.getId());
folder.addFile(copyFile);
DriveApp.getRootFolder().removeFile(copyFile);}
Result:
enter image description here
From Google Apps Script documentation:
If your custom function throws the error message "You do not have permission to call X service.", the service requires user authorization and thus cannot be used in a custom function.
The solution is to create a custom menu for your spreadsheet and execute your function upon clicking on the menu item.
function onOpen(){
var ui = SpreadsheetApp.getUi();
ui.createMenu('Menu')
.addItem('Menu item', 'yourFunc')
.addToUi();
}
function yourFunc(){
//your code
}
Hope this is helpful.
I have a workflow that sends emails out. When a user receives the email, there is a hyperlink called Review. When user clicks on Review, the value of the column called ReviewStatus on the Improvement List will be changed to Requested. I have a script below that handles this on a Content Editor Web Part:
<script language="javascript" type="text/javascript">
_spBodyOnLoadFunctionNames.push("getSetListItem");
var listItem;
var list;
var clientContext;
var siteUrl = "https://contoso.com/process/";
function getSetListItem() {
this.clientContext = new SP.ClientContext(siteUrl);
if (this.clientContext != undefined && clientContext != null) {
var webSite = clientContext.get_web();
var itemID = parseInt(GetUrlKeyValue('ID'));
this.list = webSite.get_lists().getByTitle("Improvement");
this.listItem = list.getItemById(itemID);
clientContext.load(this.listItem);
this.clientContext.executeQueryAsync(Function.createDelegate(this, this.OnLoadSuccess),
Function.createDelegate(this, this.OnLoadFailed));
}
}
function OnLoadSuccess(sender, args) {
var value = this.listItem.get_item("ReviewStatus");
this.listItem.set_item("ReviewStatus", "Requested");
this.listItem.update();
this.clientContext.load(this.listItem);
this.clientContext.executeQueryAsync(Function.createDelegate(this, this.OnLoadSuccess1),
Function.createDelegate(this, this.OnLoadFailed));
}
function OnLoadSuccess1(sender, args) {
alert(this.listItem.get_item("ReviewStatus"));
}
function OnLoadFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
</script>
The above works for me but I have Site Col Admin permissions. When a user with Read permissions clicks on the hyperlink it takes them to the page where the CEWP is and they get the below message:
I know it's permissions but what can I do to make it work for users who doesn't have the permissions? By the way, the client wants to keep the permissions to Read Only for users so there's nothing I can do about that.
Any help is appreciated.
By design, javascript code cannot run with elevated privileges because every user in nowadays browsers can just add javascript to edit (i'm talking browser developer tools).
That would of course be very risky for your project :)
You can create a farm solution if you want code to run in elevated privileges if you really don't want to change the permission settings.
If you want to keep your script, then you will have to modify the permissions for the users executing the scripts
I'm trying to make Firefox add-on that could set data to specific text or password field in any web site how could I script this add on ??
ex: I want to log in my Gmail using this add-on where I'll store my account data on it. How I could pass my username and password from my add-on to Gmail website?
I've tried to run this code
XULSchoolChrome.BrowserOverlay = {
sayHello : function(aEvent) {
let user= document.getElementById("username");
let pass= document.getElementById("passwd");
window.alert("the username is "+ user.getString);
}
};
I'm running my add-on in yahoo log-in page ...
I found the solution guys you have to use gbrowser as followed
var currenttabIndex = gBrowser.tabContainer.getIndexOfItem(gBrowser.selectedTab);
var currentBrowser = gBrowser.getBrowserAtIndex(currenttabIndex);
var inputElementlist = currentBrowser.contentDocument.getElementsByTagName("input");