DocsList Functions Not Working in Sheets Script - javascript

I'm a beginner at this, so this error might be on account of faulty coding, but this is why I'm here! lol.
I have written a Sheets function that (in theory) would go through all the files in a particular folder and find all the instances of a particular word and then return the number of instances of that word. Here is the code I wrote:
function commentCount(name) {
var files = DocsList.getFolderById('FOLDER ID GOES HERE').getFiles();
var counter = 0;
for(i in files) {
var doc = DocumentApp.openById(files[i].getId());
var text = doc.getText();
text = text.replace( /\./g, "" );
var textArray = text.split(" ");
for(w in textArray){
if(textArray[w] == name){
counter++;
}
}
}
return counter;
}
When I call the function in Sheets, an error reads - Error: You do not have permission to call getFolderById (line 3, file "commentCount")
I've tried using getFolder("Folder name"), and getFolder(path), and the same error occurs. It seems that the DocList functions are not working correctly.
Not sure what the issue is because everything seems fine when I debug the function.
I won't be able to figure out if the rest of my code is sound until I figure out this error. Any help would be greatly appreciated!

Phil Bozak clarified that formulas in Spreadsheets that call scripts functions do not get full permissions, which makes it impossible to use getFolderByID function in this case.

Related

Calling a function within a function (invoke) in Google Apps Script

I'm automating some processes within Google Apps Script.
I have created a few functions that are currently independent from each other.
However now, I want to regroup them so's they are triggered within the "master" function.
function master(){
// code that imports data from a form and organises it
runMeAfterMaster();
}
function runMeAfterMaster(){
// code that should run after master
}
Both are in the same script file, both work independently but I can't seem to just be able to "invoke" or call my other function within the master one.
Please Help!
I ran into a similar issue when my function names started with lower case letters.
the error I got was:
TypeError: randomNumber is not a function
my code:
/*
goal of the script is to highlight project rotators
*/
function HightlightProject()
{
// get random number
var randomNumber = randomNumber();
}
function randomNumber()
{
// get cell from certain spread sheet
var cell = SpreadsheetApp.getActiveSpreadsheet().getRange("fundation rotator!B7");
// random number
var number = Math.floor(Math.random() * 100);
// set random number
cell.setValue(number);
}
if I capitalize randomNumber to RandomNumber, the function names turn pink, and it works.
/*
goal of the script is to highlight project rotators
*/
function HightlightProject()
{
// get random number
var randomNumber = RandomNumber();
}
function RandomNumber()
{
// get cell from certain spread sheet
var cell = SpreadsheetApp.getActiveSpreadsheet().getRange("fundation rotator!B7");
// random number
var number = Math.floor(Math.random() * 100);
// set random number
cell.setValue(number);
}
What you wrote is ok runMeAfterMaster look to be invoked, I suppose your problem is elsewhere have you decorated your functions with Logger.log?
eg:
function master(){
// code that imports data from a form and organises it
Logger.log("I'm in master now");
runMeAfterMaster();
Logger.log("still in master but after calling runMeAfterMaster");
}
function runMeAfterMaster(){
Logger.log("I'm in runMeAfterMaster now");
// code that should run after master
Logger.log("getting out of runMeAfterMaster");
}
if you can't use Logger.log because the function is triggered automatically (and you can't have a look at the logs) yoo can replace it by your own loggin function that write everything in a spreadsheet:
function logit(message) {
SpreadsheetApp.openById("SPREADSHEET_ID").getActiveSheet().appendRow([new Date(),message]);
}
then it will become:
function master(){
// code that imports data from a form and organises it
logit("I'm in master now");
runMeAfterMaster();
logit("still in master but after calling runMeAfterMaster");
}
function runMeAfterMaster(){
logit("I'm in runMeAfterMaster now");
// code that should run after master
logit("getting out of runMeAfterMaster");
}
Harold's tips put me on the right path. The path to testing things out.
I placed my code in a code editor (in my case Brackets) and ran it through JSLint. To find any errors.
No errors there, even though the curly bracket at the end of the function name was red. It turns out over 100 lines of code in google apps and the curly bracket turns red. Under 100 lines you're good to go!
Unfortunately i couldn't debug.
So i decided to make it simpler and call both functions within a new one. That didn't work...and I still ignore why.
function MasterOfAll(){
Master();
runAfterMaster();
}
Second thing I did was to simply regroup both code of each function in a new one and call it. That worked.
function MasterOfAll(){
//Code from the Master function.
//Code from the runAfterMasterFunction.
}
Needless to say, I'm not a big fan of this solution (unclear, messy) but it works!

AngularJS infinite-scroll issue

I'm trying to use infinite-scroll to lazy load images. I'm getting the following error when it's called though:
TypeError: undefined is not a function
at handler (http://onfilm.us/ng-infinite-scroll.js:31:34)
Here's a very watered down look of what I have thus far.
function tagsController($scope) {
$scope.handleClick = function(tags) {
// Parse Tags
$scope.finished_tags = parsed_data;
};
$scope.$emit( 'handleEmit', { tags = $scope.finished_tags; });
};
function imagesController($scope,$http) {
var rows_per = 5;
$scope.$on('handleBroadcast', function(event, args) {
// Sort the images here, put them in matrix
// Example: matrix[row_number] = { picture1, picture2, picture3 }
$scope.data = matrix;
$scope.loadMore();
};
$scope.loadMore() = function() {
var last = $scope.images.length;
for ( var i = 0; i < rows_per; i++ ) {
$scope.images[last + i] = new Array();
$scope.images[last + i] = $scope.data[last + i].slice( 0 );
}
}
}
The rough idea is that the page loads the first time (w/ no tags) and get images from a PHP script. All of them. They are stored, and loadMore() is called which will populate $scope.images with 5 rows of images. It does, and they are loaded.
The line in that script is accessing $window.height and $window.scrollup. I'm still pretty green w/ Javascript, so feel free to lambast me if I'm doing something horribly wrong.
This is the broken version I'm testing with:
http://onfilm.us/test.html
Here is a version before the lazy loading was implemented, if seeing how the tags work will help. I don't think that's the issue here though.
http://onfilm.us/image_index.html
EDIT: I do think this is a problem w/ the ng-infinite-scroll.js script. The error is on line 31 (of version 1.0.0). It's telling me:
TypeError: undefined is not a function
It doesn't like $window apparently.
My JS Kung Fu is not really equipped to say why. YOu can see a literal copy/paste job from the simple demo here (with the error) onfilm.us/scroll2.html
By refering your site, It appears at first instance that your HTML-markup is not appropriate. You should move infinite-scroll to the parent of ng-repeat directive so that it will not make overlapping calls for each row generated. Please visit http://binarymuse.github.io/ngInfiniteScroll/demo_basic.html

onClick replace /segment/ of img src path with one of number of values

No idea what I'm doing or why it isn't working. Clearly not using the right method and probably won't use the right language to explain the problem..
Photogallery... Trying to have a single html page... it has links to images... buttons on the page 'aim to' modify the path to the images by finding the name currently in the path and replacing it with the name of the gallery corresponding to the button the user clicked on...
example:
GALLERY2go : function(e) {
if(GalleryID!="landscapes")
{
var find = ''+ findGalleryID()+'';
var repl = "landscapes";
var page = document.body.innerHTML;
while (page.indexOf(find) >= 0) {
var i = page.indexOf(find);
var j = find.length;
page = page.substr(0,i) + repl + page.substr(i+j);
document.body.innerHTML = page;
var GalleryID = "landscapes";
}
}
},
There's a function higher up the page to get var find to take the value of var GalleryID:
var GalleryID = "portfolio";
function findGalleryID() {
return GalleryID
}
Clearly the first varGalleryID is global (t'was there to set a default value should I have been able to find a way of referring to it onLoad) and the one inside the function is cleared at the end of the function (I've read that much). But I don't know what any of this means.
The code, given its frailties or otherwise ridiculousness, actually does change all of the image links (and absolutely everything else called "portfolio") in the html page - hence "portfolio" becomes "landscapes"... the path to the images changes and they all update... As a JavaScript beginner I was pretty chuffed to see it worked. But you can't click on another gallery button because it's stuck in a loop of some sort. In fact, after you click the button you can't click on anything else and all of the rest of the JavaScript functionality is buggered. Perhaps I've introduced some kind of loop it never exits. If you click on portfolio when you're in portfolio you crash the browser! Anyway I'm well aware that 'my cobbled together solution' is not how it would be done by someone with any experience in writing code. They'd probably use something else with a different name that takes another lifetime to learn. I don't think I can use getElement by and refer to the class/id name and parse the filename [using lots of words I don't at all understand] because of the implications on the other parts of the script. I've tried using a div wrapper and code to launch a child html doc and that come in without disposing of the existing content or talking to the stylesheet. I'm bloody lost and don't even know where to start looking next.
The point is... And here's a plea... If any of you do reply, I fear you will reply without the making the assumption that you're talking to someone who really hasn't got a clue what AJAX and JQuery and PHP are... I have searched forums; I don't understand them. Please bear that in mind.
I'll take a stab at updating your function a bit. I recognize that a critique of the code as it stands probably won't help you solve your problem.
var currentGallery = 'landscape';
function ChangeGallery(name) {
var imgs = document.getElementsByTagName("img") // get all the img tags on the page
for (var i = 0; i < imgs.length; i++) { // loop through them
if (imgs[i].src.indexOf(currentGallery) >= 0) { // if this img tag's src contains the current gallery
imgs[i].src = imgs[i].src.replace(currentGallery, name);
}
}
currentGallery = name;
}
As to why I've done what I've done - you're correct in that the scope of the variables - whether the whole page, or only the given function, knows about it, is mixed in your given code. However, another potential problem is that if you replace everything in the html that says 'landscape' with 'portfolio', it could potentially change non-images. This code only finds images, and then replaces the src only if it contains the given keyword.

SharePoint 2010 client javascript code from dialog box page

I am using code in an aspx page (javascript) that is displayed using the sharepoint 2010 UI framework dialog functions.
However, it throws an error. I can't get at the exact details. But here's the code
function DoReject(rejectype) {
rejecttype = rejectype;
this.clientContext = new SP.ClientContext.get_current();
var targetList = clientContext.get_web().get_lists().getByTitle('Applications');
var qs =window.location.search.substring(1);
var arrs = qs.substring(0,qs.indexOf('&',0)).replace('arr=','').split(',');
for (var i = 0; i < arrs.length;i++) {
k = arrs[i];
if (k != null && k != '') {
try {
this.applicant = targetList.getItemById(k);
applicant.set_item('ApplicationStatus', 'REJECTED');
applicant.update();
clientContext.executeQueryAsync(Function.createDelegate(this, this.doNothingReject), Function.createDelegate(this, this.rejectError));
this.applicant = targetList.getItemById(k);
clientContext.load(applicant, 'EMail', 'CrisDBID', 'ApplyJobTitle', 'JobRef', 'BrandId');
clientContext.executeQueryAsync(Function.createDelegate(this, this.DoRejectSuccess), Function.createDelegate(this, this.rejectError2));
}
catch (e) {
alert(e);
}
}
}
}
Note i haven't included the success / error methods, as they are superfluous in this. And the ids return correctly - they are passed into the query string. So the variable k is definitely the id of the list item.
In the error event rejectError, I use the signature
rejectError(e)
Does anyone know how to get the error details from the parameter / whats wrong with the code?
is it possible to call list operations on a page that isn't the native list page using the javascript object model?
thanks in advance
M
What browser do you get the error in? Is the error consistent between browsers? I would recommend that you debug the javascript and look at the variables at the line before it fails to see what's going on.
On a side note the first snippet you pasted looks like a standard train-wreck so if the code fails there it's likely one of these are undefined (if clientContext, get_web() or get_lists() does not return a value). I don't know anything about Sharepoint UI framework so "list operation" etc doesn't say much to me.

jQuery - javascript error - cisco web vpn

I have a very unique situation.
We use a Cisco Web VPN (don't know the exact name) here at work.
If I try to use the web pages I've developed, the javascript is broken.
I have tracked it down to this:
When using the Cisco Web VPN it will actually rewrite some of the HTML/JavaScript code.
For instance, at the very beginning of the source it has stuck the following:
<script id='CSCO_GHOST' src="/+CSCOL+/cte.js"></script>
This is directly after the <html> begin tag (and not inside the <head> tags).
Inside of that source, cte.js, there is an error. That error is causing jQuery to not function properly. cte.js is part of Cisco's product and is totally out of my control.
I know how to capture errors with the windows.onerror but that is not working for this situation. The error is occurring before my scripts are loaded into the page.
Any ideas on how to suppress this error or work around such a thing?
I had my <script> tags in the <head> and then moved them to the bottom of the <body> and in neither place does it make a difference.
UPDATE:
After a bit more looking, it is something in jQuery. I commented out the <script> tag for jQuery and the error did not happen. Uncommented, the error came back.
This is what I had to do to fix the problem. I created a JS file in my web project with the following code:
if ( typeof SegmentHtml != "undefined" ) {
SegmentHtmlParam.prototype['filter'] = function() {
var name = null;
var value = null;
for (var i = 1; i < this._tokens.length; i++) {
var token = this._tokens[i];
if (token.type === ATTR_NAME) {
name = csco_g_buffer.substring(token.first_index, token.last_index).toUpperCase();
} else if (token.type === ATTR_VALUE) {
value = csco_g_buffer.substring(token.first_index, token.last_index);
};
};
var need_processing = false;
if (ParserClsidName) {
var tmp = ParserClsidName[this._clsid];
if (tmp) {
var proc = tmp[name];
need_processing = typeof proc != 'undefined';
};
};
/**
* ERROR ON NEXT LINE: name is null
*/
if (name!=null && name.toLowerCase() == "csco_proto") {
this._parent['csco_proto'] = value;
};
if (need_processing) { this._parent[name] = value; };
};
};
This is the FIRST javascript file I include in my HTML file.
<script type="text/javascript" src="js/jQueryCiscoKludge.js"></script>
I am running into this issue as well. It is really messed up for Cisco to just rewrite JS code like that, assuming it'll work for every single code on the web. There are some serious irreversible consequence like scope loss that will screw everything up. Who in their right mind would do that in the name of "security"? And what is preventing us from overriding the JS code they have injected?

Categories