I wrote a script that restores calendar data from a backup written in a spreadsheet. Since the amount of data is extremely unpredictable, I developed a cycle that stops after a given number of minutes, asking the user to continue or cancel , showing the actual state of the counter (this prevents the problem with the maximum Google max execution time).
This works very well, but in this simplified test script that I used to test the idea, it works only once: when the first "timeout" occurs, it shows the continue/cancel option, as expected, and then continues from there places where it was started but when the same condition occurs a second time , the continue button is not displayed.
My question is simple: why? or better: what's the difference between both situations?
A spreadsheet with an inline script publicly checked here (see menu : test )
and the whole script is shown below (this is a little longer, of course, but the interesting part is closer to the end)
I used ScriptProperties to track the runtime and continue the loop I left.
function onOpen() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var menuEntries = [ {name: "test", functionName: "test"}, ]; ss.addMenu("test", menuEntries); } function test(){ ScriptProperties.setProperty('restorePointers',[0,0].join('@')) var app = UiApp.createApplication().setTitle("test"); app.setHeight(150).setWidth(250); var doc = SpreadsheetApp.getActiveSpreadsheet(); var panel = app.createVerticalPanel(); var handlerCancel = app.createServerHandler('canceltest'); var handlerContinue = app.createServerHandler('continuetest'); var contCHandler = app.createClientHandler(); var cancel = app.createButton("cancel.", handlerCancel).setId('cancel').setVisible(false); var cont = app.createButton('continue',handlerContinue).setId('continue').setVisible(false).addClickHandler(contCHandler); var button = app.createButton('start').setId('button'); var handler = app.createServerClickHandler('runtest'); handler.addCallbackElement(panel); contCHandler.forTargets(button).setEnabled(false).forEventSource().setVisible(false); var cHandler = app.createClientHandler().forTargets(cancel).setVisible(true).forEventSource().setVisible(false); button.addClickHandler(handler).addClickHandler(cHandler); app.add(panel.add(button).add(cont).add(cancel))//.add(trig)); doc.show(app); } function canceltest(e){ var app = UiApp.getActiveApplication(); ScriptProperties.setProperty('restoreData','') ScriptProperties.setProperty('restorePointers','canceled'); SpreadsheetApp.getActiveSpreadsheet().toast(' ','restore aborted'); app.close() return app; } function continuetest(e){ runtest(e) } function runtest(e){ var dStart; var dEnd; ScriptProperties.setProperty('startrestore',new Date().getTime().toString()) if(ScriptProperties.getProperty('restoreData')==null||Utilities.jsonStringify(ScriptProperties.getProperties()).indexOf('restoreData')==-1) {ScriptProperties.setProperty('restoreData',Utilities.jsonStringify(e)) } var app = UiApp.getActiveApplication(); var pointers = ScriptProperties.getProperty('restorePointers'); if(pointers==' 0@0 '){ dStart = 0; dEnd = 500; }else{ dStart = Number(pointers.split('@')[0]); dEnd = Number(pointers.split('@')[1]); } // main loop -------------------------- for(var ee=dStart;ee<dEnd;++ee){ // main loop var ccc = ScriptProperties.getProperty('restorePointers'); if(ccc=='canceled'){ app.close();return app}; Utilities.sleep(85); // simulate some activity if((ee/10)==parseInt(ee/10)&&ee>0){ SpreadsheetApp.getActiveSpreadsheet().toast(ee+' steps completed') if(new Date().getTime()-Number(ScriptProperties.getProperty('startrestore'))>12000){ ;// +- 12 sec timeout ScriptProperties.setProperty('restorePointers',[ee,dEnd].join('@')); app.getElementById('continue').setHTML('continue from '+ee).setVisible(true) return app } } } // end of main loop----------------- ScriptProperties.setProperty('restoreData','') ScriptProperties.setProperty('restorePointers',0+'@'+0); SpreadsheetApp.getActiveSpreadsheet().toast('normal process end'); app.close(); return app; }