Guessing Number Game Program not Functioning Correctly - actionscript-3

in my program, the user sets a range of numbers for the computer to guess. The user then has to guess which number the computer chose with a limit of guesses starting at 5. There are several problems in my functioning program in which I do not understand how to fix. These errors include:
-The number of guesses left always remains at 0. It won't start at 5 and decrease by 1 each time I click the btnCheck button.
-Whenever I click the btnCheck button for a new guessing number, the statement if you've guessed too high or too low remains the same.
-When I press btnNewGame, the values I insert in my low value and my high value text inputs will not be cleared.
-How can the computer generate a random whole number based on what I set as the number range?
Revising my code down below will be much appreciated.
// This line makes the button, btnCheckGuess wait for a mouse click
// When the button is clicked, the checkGuess function is called
btnCheckGuess.addEventListener(MouseEvent.CLICK, checkGuess);
// This line makes the button, btnNewGame wait for a mouse click
// When the button is clicked, the newGame function is called
btnNewGame.addEventListener(MouseEvent.CLICK, newGame);
// Declare Global Variables
var computerGuess:String; // the computer's guess
var Statement:String; // Statement based on your outcome
// This is the checkGuess function
// e:MouseEvent is the click event experienced by the button
// void indicates that the function does not return a value
function checkGuess(e:MouseEvent):void
{
var LowValue:Number; // the user's low value
var HighValue:Number; // the user's high value
var UserGuess:Number; // the user's guess
var CorrectGuess:int; // the correct number
var FirstGuess:String; //the user's guess
// get the user's range and guess
LowValue = Number(txtinLow.text);
HighValue = Number(txtinHigh.text);
UserGuess = Number(txtinGuess.text);
// determine the number of the user
GuessesLeft = checkCorrectGuess(FirstGuess);
lblNumber.text = GuessesLeft.toString();
lblStatement.text = "You have guessed " + Statement.toString() + "\r";
}
// This is function checkColoursCorrect
// g1– the user's guess
function checkCorrectGuess(g1:String):int
{
var GuessesLeft:int = 5; // How many guesses are left
if (g1 != computerGuess)
{
GuessesLeft - 1;
}
else
{
GuessesLeft = 0;
}
return GuessesLeft;
}
// This is the newGame function
// e:MouseEvent is the click event experienced by the button
// void indicates that the function does not return a value
function newGame(e:MouseEvent):void
{
var Guess1:int; // computer's guess in numbers
var UserGuess1:int; // user's guess in numbers
Guess1 = randomWholeNumber(100,1); //It is not (100,1). How do I change this to the range the user put?
UserGuess1 = randomWholeNumber(100,1); //It is not (100,1). How do I change this to the range the user put?
if (Guess1 > UserGuess1) {
Statement = "TOO HIGH";
} else if (Guess1 < UserGuess1) {
Statement = "TOO LOW";
} else if (Guess1 == UserGuess1) {
Statement = "CORRECTLY";
}
txtinGuess.text = "";
lblStatement.text = "";
}
// This is function randomWholeNumber
// highNumber – the maximum value desired
// lowNumber – the minimum value desired
// returns – a random whole number from highNumber to lowNumber inclusive
function randomWholeNumber(highNumber:int,lowNumber:int):int //How do I make a whole random number based on the range the user made?
{
return Math.floor((highNumber - lowNumber + 1) * Math.random() + lowNumber);
}

To answer your questions...
You've declared GuessesLeft inside checkCorrectGuess() which means its a local variable that's being redefined every time you call the function. Futhermore, because you're passing in var FirstGuess:String; (an uninitialized, non-referenced string variable), (g1 != computerGuess) is returning false, and the answer is always 0.
GuessesLeft - 1; is not saving the result back to the variable. You need to use an assignment operator such as GuessesLeft = GuessesLeft - 1 or simply type GuessesLeft-- if all you want is to decrement. You could also write GuessesLeft -= 1 which subtracts the right from the left, and assigns the value to the variable on the left. See AS3 Operators...
You've already assigned values to these TextFields earlier; simply repeat the process inside of newGame() with a txtinLow.text = "" (same with high)
Use your variables. You defined them earlier in checkGuess() as UserGuess, LowValue, and HighValue
Be mindful that you only need to split out functionality into separate functions if that piece of code is likely to be called elsewhere. Otherwise, every function on the stack incurs more memory and performance hits. checkCorrectGuess() falls into that category and is therefore unnecessary.
Also, you are printing your feedback to the user in the newGame() function instead of checkGuess(). It seemed like an oversight.
btnCheckGuess.addEventListener(MouseEvent.CLICK, checkGuess);
btnNewGame.addEventListener(MouseEvent.CLICK, newGame);
// Global Variables
var computerGuess:int;
var remainingGuesses:int;
newGame();
function newGame(e:MouseEvent):void {
// Reset our guess limit
remainingGuesses = 5;
// Generate a new number
computerGuess = random(int(txtinLow.text), int(txtinHigh.text));
// Reset our readouts.
txtinGuess.text = "";
lblStatement.text = "";
}
function checkGuess(e:MouseEvent):void {
var guess:int = int(txtinGuess.text);
var msg:String;
if (guess == computerGuess) { // Win
remainingGuesses = 0; // Zero our count
msg = "CORRECT";
} else { // Missed
remainingGuesses--; // Decrement our count
if (guess > computerGuess) {
msg = "TOO HIGH";
} else if (guess < computerGuess) {
msg = "TOO LOW";
}
}
lblNumber.text = remainingGuesses.toString();
lblStatement.text = "You have guessed " + msg;
}
function random(low:int, high:int):int {
return Math.floor((high - low + 1) * Math.random() + low);
}

Related

How to select all underlined text in a paragraph

I'm trying to create a google apps script that will format certain parts of a paragraph. For example, text that is underlined will become bolded/italicized as well.
One docs add-on I have tried has a similar feature: https://imgur.com/a/5Cw6Irn (this is exactly what I'm trying to achieve)
How can I write a function that will select a certain type of text and format it?
**I managed to write a script that iterates through every single letter in a paragraph and checks if it's underlined, but it becomes extremely slow as the paragraph gets longer, so I'm looking for a faster solution.
function textUnderline() {
var selectedText = DocumentApp.getActiveDocument().getSelection();
if(selectedText) {
var elements = selectedText.getRangeElements();
for (var index = 0; index < elements.length; index++) {
var element = elements[index];
if(element.getElement().editAsText) {
var text = element.getElement().editAsText();
var textLength = text.getText().length;
//For every single character, check if it's underlined and then format it
for (var i = 0; i < textLength; i++) {
if(text.isUnderline(i)) {
text.setBold(i, i, true);
text.setBackgroundColor(i,i,'#ffff00');
} else {
text.setFontSize(i, i, 8);
}
}
}
}
}
}
Use getTextAttributeIndices:
There is no need to check each character in the selection. You can use getTextAttributeIndices() to get the indices in which the text formatting changes. This method:
Retrieves the set of text indices that correspond to the start of distinct text formatting runs.
You just need to iterate through these indices (that is, check the indices in which text formatting changes), which are a small fraction of all character indices. This will greatly increase efficiency.
Code sample:
function textUnderline() {
var selectedText = DocumentApp.getActiveDocument().getSelection();
if(selectedText) {
var elements = selectedText.getRangeElements();
for (var index = 0; index < elements.length; index++) {
var element = elements[index];
if(element.getElement().editAsText) {
var text = element.getElement().editAsText();
var textRunIndices = text.getTextAttributeIndices();
var textLength = text.getText().length;
for (let i = 0; i < textRunIndices.length; i++) {
const startOffset = textRunIndices[i];
const endOffset = i + 1 < textRunIndices.length ? textRunIndices[i + 1] - 1 : textLength - 1;
if (text.isUnderline(textRunIndices[i])) {
text.setBold(startOffset, endOffset, true);
text.setBackgroundColor(startOffset, endOffset,'#ffff00');
} else {
text.setFontSize(startOffset, endOffset, 8);
}
}
}
}
}
}
Reference:
getTextAttributeIndices()
Based on the example shown in the animated gif, it seems your procedure needs to
handle a selection
set properties if the selected region is of some format (e.g. underlined)
set properties if the selected region is NOT of some format (e.g. not underlined)
finish as fast as possible
and your example code achieves all these goals expect the last one.
The problem is that you are calling the text.set...() functions at each index position. Each call is synchronous and blocks the code until the document is updated, thus your run time grows linearly with each character in the selection.
My suggestion is to build up a collection of subranges from the selection range and then for each subrange use text.set...(subrange.start, subrange.end) to apply the formatting. Now the run time will be dependent on chunks of characters, rather than single characters. i.e., you will only update when the formatting switches back and forth from, in your example, underlined to not underlined.
Here is some example code that implements this subrange idea. I separated the specific predicate function (text.isUnderline) and specific formatting effects into their own functions so as to separate the general idea from the specific implementation.
// run this function with selection
function transformUnderlinedToBoldAndYellow() {
transformSelection("isUnderline", boldYellowOrSmall);
}
function transformSelection(stylePredicateKey, stylingFunction) {
const selectedText = DocumentApp.getActiveDocument().getSelection();
if (!selectedText) return;
const getStyledSubRanges = makeStyledSubRangeReducer(stylePredicateKey);
selectedText.getRangeElements()
.reduce(getStyledSubRanges, [])
.forEach(stylingFunction);
}
function makeStyledSubRangeReducer(stylePredicateKey) {
return function(ranges, rangeElement) {
const {text, start, end} = unwrapRangeElement(rangeElement);
if (start >= end) return ranges; // filter out empty selections
const range = {
text, start, end,
styled: [], notStyled: [] // we will extend our range with subranges
};
const getKey = (isStyled) => isStyled ? "styled" : "notStyled";
let currentKey = getKey(text[stylePredicateKey](start));
range[currentKey].unshift({start: start});
for (let index = start + 1; index <= end; ++index) {
const isStyled = text[stylePredicateKey](index);
if (getKey(isStyled) !== currentKey) { // we are switching styles
range[currentKey][0].end = index - 1; // note end of this style
currentKey = getKey(isStyled);
range[currentKey].unshift({start: index}); // start new style range
}
}
ranges.push(range);
return ranges;
}
}
// a helper function to unwrap a range selection, deals with isPartial,
// maps RangeElement => {text, start, end}
function unwrapRangeElement(rangeElement) {
const isPartial = rangeElement.isPartial();
const text = rangeElement.getElement().asText();
return {
text: text,
start: isPartial
? rangeElement.getStartOffset()
: 0,
end: isPartial
? rangeElement.getEndOffsetInclusive()
: text.getText().length - 1
};
}
// apply specific formatting to satisfy the example
function boldYellowOrSmall(range) {
const {text, start, end, styled, notStyled} = range;
styled.forEach(function setTextBoldAndYellow(range) {
text.setBold(range.start, range.end || end, true);
text.setBackgroundColor(range.start, range.end || end, '#ffff00');
});
notStyled.forEach(function setTextSmall(range) {
text.setFontSize(range.start, range.end || end, 8);
});
}

Can Google apps script be used to randomize page order on Google forms?

Update #2: Okay, I'm pretty sure my error in update #1 was because of indexing out of bounds over the array (I'm still not used to JS indexing at 0). But here is the new problem... if I write out the different combinations of the loop manually, setting the page index to 1 in moveItem() like so:
newForm.moveItem(itemsArray[0][0], 1);
newForm.moveItem(itemsArray[0][1], 1);
newForm.moveItem(itemsArray[0][2], 1);
newForm.moveItem(itemsArray[1][0], 1);
newForm.moveItem(itemsArray[1][1], 1);
newForm.moveItem(itemsArray[1][2], 1);
newForm.moveItem(itemsArray[2][0], 1);
...
...I don't get any errors but the items end up on different pages! What is going on?
Update #1:: Using Sandy Good's answer as well as a script I found at this WordPress blog, I have managed to get closer to what I needed. I believe Sandy Good misinterpreted what I wanted to do because I wasn't specific enough in my question.
I would like to:
Get all items from a page (section header, images, question etc)
Put them into an array
Do this for all pages, adding these arrays to an array (i.e: [[all items from page 1][all items from page 2][all items from page 3]...])
Shuffle the elements of this array
Repopulate a new form with each element of this array. In this way, page order will be randomized.
My JavaScript skills are poor (this is the first time I've used it). There is a step that produces null entries and I don't know why... I had to remove them manually. I am not able to complete step 5 as I get the following error:
Cannot convert Item,Item,Item to (class).
"Item,Item,Item" is the array element containing all the items from a particular page. So it seems that I can't add three items to a page at a time? Or is something else going on here?
Here is my code:
function shuffleForms() {
var itemsArray,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,shuffle, sections;
// Copy template form by ID, set a new name
newFormFile = DriveApp.getFileById('1prfcl-RhaD4gn0b2oP4sbcKaRcZT5XoCAQCbLm1PR7I')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
// Get ID of new form and open it
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
// Initialize array to put IDs in
itemsArray = [];
function getPageItems(thisPageNum) {
Logger.log("Getting items for page number: " + thisPageNum );
var thisPageItems = []; // Used for result
var thisPageBreakIndex = getPageItem(thisPageNum).getIndex();
Logger.log( "This is index num : " + thisPageBreakIndex );
// Get all items from page
var allItems = newForm.getItems();
thisPageItems.push(allItems[thisPageBreakIndex]);
Logger.log( "Added pagebreak item: " + allItems[thisPageBreakIndex].getIndex() );
for( var i = thisPageBreakIndex+1; ( i < allItems.length ) && ( allItems[i].getType() != FormApp.ItemType.PAGE_BREAK ); ++i ) {
thisPageItems.push(allItems[i]);
Logger.log( "Added non-pagebreak item: " + allItems[i].getIndex() );
}
return thisPageItems;
}
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
Logger.log('shuffle ran')
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function shuffleAndMove() {
// Get page items for all pages into an array
for(i = 2; i <= 5; i++) {
itemsArray[i] = getPageItems(i);
}
// Removes null values from array
itemsArray = itemsArray.filter(function(x){return x});
// Shuffle page items
itemsArray = shuffle(itemsArray);
// Move page items to the new form
for(i = 2; i <= 5; ++i) {
newForm.moveItem(itemsArray[i], i);
}
}
shuffleAndMove();
}
Original post: I have used Google forms to create a questionnaire. For my purposes, each question needs to be on a separate page but I need the pages to be randomized. A quick Google search shows this feature has not been added yet.
I see that the Form class in the Google apps script has a number of methods that alter/give access to various properties of Google Forms. Since I do not know Javascript and am not too familiar with Google apps/API I would like to know if what I am trying to do is even possible before diving in and figuring it all out.
If it is possible, I would appreciate any insight on what methods would be relevant for this task just to give me some direction to get started.
Based on comments from Sandy Good and two SE questions found here and here, this is the code I have so far:
// Script to shuffle question in a Google Form when the questions are in separate sections
function shuffleFormSections() {
getQuestionID();
createNewShuffledForm();
}
// Get question IDs
function getQuestionID() {
var form = FormApp.getActiveForm();
var items = form.getItems();
arrayID = [];
for (var i in items) {
arrayID[i] = items[i].getId();
}
// Logger.log(arrayID);
return(arrayID);
}
// Shuffle function
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i--) {
j = Math.floor(Math.random() * i);
x = a[i - 1];
a[i - 1] = a[j];
a[j] = x;
}
}
// Shuffle IDs and create new form with new question order
function createNewShuffledForm() {
shuffle(arrayID);
// Logger.log(arrayID);
var newForm = FormApp.create('Shuffled Form');
for (var i in arrayID) {
arrayID[i].getItemsbyId();
}
}
Try this. There's a few "constants" to be set at the top of the function, check the comments. Form file copying and opening borrowed from Sandy Good's answer, thanks!
// This is the function to run, all the others here are helper functions
// You'll need to set your source file id and your destination file name in the
// constants at the top of this function here.
// It appears that the "Title" page does not count as a page, so you don't need
// to include it in the PAGES_AT_BEGINNING_TO_NOT_SHUFFLE count.
function shuffleFormPages() {
// UPDATE THESE CONSTANTS AS NEEDED
var PAGES_AT_BEGINNING_TO_NOT_SHUFFLE = 2; // preserve X intro pages; shuffle everything after page X
var SOURCE_FILE_ID = 'YOUR_SOURCE_FILE_ID_HERE';
var DESTINATION_FILE_NAME = 'YOUR_DESTINATION_FILE_NAME_HERE';
// Copy template form by ID, set a new name
var newFormFile = DriveApp.getFileById(SOURCE_FILE_ID).makeCopy();
newFormFile.setName(DESTINATION_FILE_NAME);
// Open the duplicated form file as a form
var newForm = FormApp.openById(newFormFile.getId());
var pages = extractPages(newForm);
shuffleEndOfPages(pages, PAGES_AT_BEGINNING_TO_NOT_SHUFFLE);
var shuffledFormItems = flatten(pages);
setFormItems(newForm, shuffledFormItems);
}
// Builds an array of "page" arrays. Each page array starts with a page break
// and continues until the next page break.
function extractPages(form) {
var formItems = form.getItems();
var currentPage = [];
var allPages = [];
formItems.forEach(function(item) {
if (item.getType() == FormApp.ItemType.PAGE_BREAK && currentPage.length > 0) {
// found a page break (and it isn't the first one)
allPages.push(currentPage); // push what we've built for this page onto the output array
currentPage = [item]; // reset the current page to just this most recent item
} else {
currentPage.push(item);
}
});
// We've got the last page dangling, so add it
allPages.push(currentPage);
return allPages;
};
// startIndex is the array index to start shuffling from. E.g. to start
// shuffling on page 5, startIndex should be 4. startIndex could also be thought
// of as the number of pages to keep unshuffled.
// This function has no return value, it just mutates pages
function shuffleEndOfPages(pages, startIndex) {
var currentIndex = pages.length;
// While there remain elements to shuffle...
while (currentIndex > startIndex) {
// Pick an element between startIndex and currentIndex (inclusive)
var randomIndex = Math.floor(Math.random() * (currentIndex - startIndex)) + startIndex;
currentIndex -= 1;
// And swap it with the current element.
var temporaryValue = pages[currentIndex];
pages[currentIndex] = pages[randomIndex];
pages[randomIndex] = temporaryValue;
}
};
// Sourced from elsewhere on SO:
// https://stackoverflow.com/a/15030117/4280232
function flatten(array) {
return array.reduce(
function (flattenedArray, toFlatten) {
return flattenedArray.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
},
[]
);
};
// No safety checks around items being the same as the form length or whatever.
// This mutates form.
function setFormItems(form, items) {
items.forEach(function(item, index) {
form.moveItem(item, index);
});
};
I tested this code. It created a new Form, and then shuffled the questions in the new Form. It excludes page breaks, images and section headers. You need to provide a source file ID for the original template Form. This function has 3 inner sub-functions. The inner functions are at the top, and they are called at the bottom of the outer function. The arrayOfIDs variable does not need to be returned or passed to another function because it is available in the outer scope.
function shuffleFormSections() {
var arrayOfIDs,shuffleQuestionsInNewForm,fncGetQuestionID,
newFormFile,newForm,newID,items,shuffle;
newFormFile = DriveApp.getFileById('Put the source file ID here')
.makeCopy();
newFormFile.setName('AAAAA_Shuffled_Form');
newID = newFormFile.getId();
newForm = FormApp.openById(newID);
arrayOfIDs = [];
fncGetQuestionID = function() {
var i,L,thisID,thisItem,thisType;
items = newForm.getItems();
L = items.length;
for (i=0;i<L;i++) {
thisItem = items[i];
thisType = thisItem.getType();
if (thisType === FormApp.ItemType.PAGE_BREAK ||
thisType === FormApp.ItemType.SECTION_HEADER ||
thisType === FormApp.ItemType.IMAGE) {
continue;
}
thisID = thisItem.getId();
arrayOfIDs.push(thisID);
}
Logger.log('arrayOfIDs: ' + arrayOfIDs);
//the array arrayOfIDs does not need to be returned since it is available
//in the outermost scope
}// End of fncGetQuestionID function
shuffle = function() {// Shuffle function
var j, x, i;
Logger.log('shuffle ran')
for (i = arrayOfIDs.length; i; i--) {
j = Math.floor(Math.random() * i);
Logger.log('j: ' + j)
x = arrayOfIDs[i - 1];
Logger.log('x: ' + x)
arrayOfIDs[i - 1] = arrayOfIDs[j];
arrayOfIDs[j] = x;
}
Logger.log('arrayOfIDs: ' + arrayOfIDs)
}
shuffleQuestionsInNewForm = function() {
var i,L,thisID,thisItem,thisQuestion,questionType;
L = arrayOfIDs.length;
for (i=0;i<L;i++) {
thisID = arrayOfIDs[i];
Logger.log('thisID: ' + thisID)
thisItem = newForm.getItemById(thisID);
newForm.moveItem(thisItem, i)
}
}
fncGetQuestionID();//Get all the question ID's and put them into an array
shuffle();
shuffleQuestionsInNewForm();
}

STRING COMPARSION FLASH AS3

I got an input textfield in the UI.
When user key in "GIRAFFEEE", "GIRAFEAAA" OR "GIRAFFE123" and submit. The score value should be 0. However it returns 1.
How do I compare case sensitive string correctly?
qns1 = qns1_txt.text.toLowerCase();
qns1Ans = "giraffe"
//.toLowerCase();
if (qns1 == qns1Ans)
{
score = 1;
}
else
{
score = 0;
}
If you test following:
var correct:String = "giraffe";
var userAns:String = "giraffeaaaa";
trace(correct == userAns);//false - as expected
it means that string comparison works:)
I assume that your test code is in the CHANGE event of the textfield which may result in false positive as user may type part of correct answer, I think you should do a function:
function validate()
{
qns1 = qns1_txt.text.toLowerCase();
qns1Ans = "giraffe"
score = 0;
if(qns1 == qns1Ans)
{
score = 1;
}
}
and call it when user will hit submit, you could also compare the length of strings but equal operator will do just fine.

"Error Encountered: Invalid Argument" in handler function

I'm getting this error in my handler function but I've no clue what's causing it. I've copied the code and debugged it in a non-handler function and there was no error.
function _responseToNext(e) {
var app = UiApp.getActiveApplication();
app.getElementById('btnPrev').setEnabled(true);
var current = parseInt(CacheService.getPublicCache().get('currentItem'));
var agendaItems = Utilities.jsonParse(CacheService.getPublicCache().get('agenda'));
agendaItems[current]['notes'] = e.parameter.tAreaNotes;
agendaItems[current]['status'] = e.parameter.lboxStatus;
CacheService.getPublicCache().put('agenda', Utilities.jsonStringify(agendaItems));
current = current + 1;
CacheService.getPublicCache().put('currentItem', current);
fillAgendaDetail(app);
// only enabled 'Next' if there are more items in the agenda
if (current < agendaItems.length-1) {
app.getElementById('btnNext').setEnabled(true);
}
return app;
}
I suppose, the error cause is that the Cache get method returns null during the 1st execution when the cache is empty. The Utilities.jsonParse throws an exception and the cache becomes in any case empty. Try to use the following modified code.
function _responseToNext(e) {
var app = UiApp.getActiveApplication();
app.getElementById('btnPrev').setEnabled(true);
var cachedCurrent = CacheService.getPublicCache().get('currentItem');
var current;
if (cachedCurrent == null) {
current = 0;
}
else {
current = parseInt(cachedCurrent);
}
var cachedAgendaItems = CacheService.getPublicCache().get('agenda');
var agendaItems;
if (cachedAgendaItems == null) {
agendaItems = [][];
}
else {
agendaItems = Utilities.jsonParse();
}
agendaItems[current]['notes'] = e.parameter.tAreaNotes;
agendaItems[current]['status'] = e.parameter.lboxStatus;
CacheService.getPublicCache().put('agenda', Utilities.jsonStringify(agendaItems));
current = current + 1;
CacheService.getPublicCache().put('currentItem', current);
fillAgendaDetail(app);
// only enabled 'Next' if there are more items in the agenda
if (current < agendaItems.length-1) {
app.getElementById('btnNext').setEnabled(true);
}
return app;
}
Also please mention that the Public Cache (CacheService.getPublicCache()) is the same for all users of your script. In your case, this means, if two users user1#example.com and user2#example.com use the script they will have the same current and agendaItems variables values, i.e. it can be a situation when the _responseToNext handler is already executed under the user1 authority - the current variable is equal to 1, after the user2 executes the _responseToNext handler - the current variable is equal to 2 and so on. If you do not need such behaviour, use the CacheService.getPrivateCache().

function within a loop within a function?

I'm coding an email verification form in 3 parts.
Part 1 - check a single character against a list of allowed characters and return true/false.
Part 2 - check a string of characters as the part before or after the '#' using a loop calling the previous function to each successive character.
Part 3 - check a complete email that it includes only one '#', the substring before and after the '#' both satisfy part 2 and the substring following the '#' has only one full stop.
I've got part 1 down but my loop for part 2 is incorrect and returning true for all input values other than a blank form. here is the code -
function isValidEmailPart(part)
{ var emailPartInput = document.getElementById("isValidPartArg").value;
var emailPartLength = alert(emailPartInput.length);
{
if (emailPartInput.length == "")
{
return (false)
}
else
{
NUMBER_OF_CHARACTERS = alert((emailPartInput.length) - 1);
var i = 0;
{for(var i=0; i<NUMBER_OF_CHARACTERS; i++)
{
function isValidEmailChar()
{ var validChars = 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,0,1,2,3,4,5,6,7,8,9,_,-,.,';
var emailPartInput = document.getElementById("isValidPartArg").value;
var charInput = emailPartInput.charAt(i);
var inputVar = validChars.indexOf(charInput);
if (inputVar < 0)
{
return (false)
}
}
}
return (true);
}
}
}
}
I know it must be something simple, there are no errors returning I have no idea what I'm doing wrong.
Please, consider the following things very carefully:
Define functions separately: you can call a function from another function BUT don't define a function inside a function
Make sure that your code is ok, pay attention to your code syntax: I found additional { for example. Usually your code editor highlights code syntax errors.
Pay attention to your code's indent: having a good indent helps you have a clearer view of your code and helps you find your potential code mistakes.
Review the different types of variables: in javascript, the variables can have different types: boolean, integer, float, string, etc. You can only compare variables of a same types (Do not mix carrots and potatoes!) and so, you cannot compare emailPartInput with an empty string "" for example.
Before reading the code bellow, you should try to search what was wrong it your code, and what has to be modified to make it work.
Check very carefully the comments I wrote in the code that follows (I took a lot of time to write them!)
The javascript functions:
// This functions verifies if a char 'my_char' is valid
function isValidEmailChar(my_char)
{
// 'my_char' is a i-th character of 'emailPartInput'
var output = false;
// 'validChars' is the array containing all the valid characters
var validChars = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'0','1','2','3','4','5','6','7','8','9','_','-','.'];
// We want to check if 'my_char' is in the array 'validChar'
// So, for each character in the array 'validChar', we check that there's at least
// 1 character in it which is equal to 'my_char'
for(var i=0; i<validChars.length; i++)
{
// 'output' is the result that the function 'isValidEmailChar' will return
// It is initially set to "false"
// The line below means: we store in 'output'
// the result of " output OR ['my_char' EQUALS the i-th character in the array 'validChars'] ".
// Which means that, in the end, 'output' will be "true" if there's at least one i-th character
// in the array 'validChars' where 'my_char' EQUALS the i-th character in the array 'validChars'.
output = (output || (my_char == validChars[i]));
}
// We return the output
// Note: It is better to define 1 'return' and not several
return output;
}
// This function verifies if a part of Email is valid
function isValidEmailPart(emailPartInput)
{
// 'emailPartInput' is the part of email
// 'output' is your function's result to be returned
var output = false;
alert("INPUT = "+emailPartInput);
var nb_of_characters = emailPartInput.length;
alert("number of characters = "+nb_of_characters);
if (nb_of_characters != 0)
{
output = true;
var i = 0;
while(output && i<nb_of_characters)
{
// 'is_character_valid' is a boolean value which is set to:
// - true: if the i-th character of 'emailPartInput' is valid
// - false: if not valid
var is_character_valid = isValidEmailChar(emailPartInput.charAt(i));
// The line below means that we store in the variable 'ouput' the result of
// 'output' AND 'is_character_valid', which means that:
// if there's at least one 'is_character_valid' set to false
// (= one i-th character of 'emailPartInput' is not valid)
// 'output' will then be equals to false
output = output && is_character_valid;
i++;
// We remark that if 'output' is false, we quit the 'while' loop
// because finding one invalid character means that 'emailPartInput' is invalid
// so, we do not need to check the other characters of 'emailPartInput'
}
}
else
{
alert("No emailPartInput has been input");
}
// We return the output
return output;
}
Here's a working example where you can test your functions:
<HTML>
<HEAD>
<SCRIPT language="javascript">
// This functions verifies if a char 'my_char' is valid
function isValidEmailChar(my_char)
{
// 'my_char' is a i-th character of 'emailPartInput'
var output = false;
// 'validChars' is the array containing all the valid characters
var validChars = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'0','1','2','3','4','5','6','7','8','9','_','-','.'];
// We want to check if 'my_char' is in the array 'validChar'
// So, for each character in the array 'validChar', we check that there's at least
// 1 character in it which is equal to 'my_char'
for(var i=0; i<validChars.length; i++)
{
// 'output' is the result that the function 'isValidEmailChar' will return
// It is initially set to "false"
// The line below means: we store in 'output'
// the result of " output OR ['my_char' EQUALS the i-th character in the array 'validChars'] ".
// Which means that, in the end, 'output' will be "true" if there's at least one i-th character
// in the array 'validChars' where 'my_char' EQUALS the i-th character in the array 'validChars'.
output = (output || (my_char == validChars[i]));
}
// We return the output
// Note: It is better to define 1 'return' and not several
return output;
}
// This function verifies if a part of Email is valid
function isValidEmailPart(emailPartInput)
{
// 'emailPartInput' is the part of email
// 'output' is your function's result to be returned
var output = false;
alert("INPUT = "+emailPartInput);
var nb_of_characters = emailPartInput.length;
alert("number of characters = "+nb_of_characters);
if (nb_of_characters != 0)
{
output = true;
var i = 0;
while(output && i<nb_of_characters)
{
// 'is_character_valid' is a boolean value which is set to:
// - true: if the i-th character of 'emailPartInput' is valid
// - false: if not valid
var is_character_valid = isValidEmailChar(emailPartInput.charAt(i));
// The line below means that we store in the variable 'ouput' the result of
// 'output' AND 'is_character_valid', which means that:
// if there's at least one 'is_character_valid' set to false
// (= one i-th character of 'emailPartInput' is not valid)
// 'output' will then be equals to false
output = output && is_character_valid;
i++;
// We remark that if 'output' is false, we quit the 'while' loop
// because finding one invalid character means that 'emailPartInput' is invalid
// so, we do not need to check the other characters of 'emailPartInput'
}
}
else
{
alert("No emailPartInput has been input");
}
// We return the output
return output;
}
function test() {
var my_input = document.getElementById("my_input").value;
var result = isValidEmailPart(my_input);
if(result)
alert("The part of email is valid");
else
alert("The part of email is NOT valid");
}
</SCRIPT>
</HEAD>
<BODY>
Enter you Email part here:
<INPUT type="text" id="my_input" value="" />
<button onclick="javascript:test();">Check the Email part!</button>
</BODY>
</HTML>
NB: The most important is to make sure that you understand what you wrote in your code and what was wrong.
I think you know that just copying a working won't be a benefit for you.
If you read my code, I hope you spent your time to understand it and to read the comments carefully (I took a lot of time to write them! :S)
You can check free online tutorials to learn javascript too! :)
Hope this helps. If you have any questions, do not hesitate to ask, I'll be glad to help.