Attempting to make a Timeout for a google script UI alert - user-interface

I am trying to figure out if I can Auto-Magically select no in a UI alert in google script..
var old = e.oldValue;
var ui = SpreadsheetApp.getUi() ;
if( old == null ){} else{
if( old == "NO"){} else {
if(e.range.getRow() == 3 ) {}
else{ var response = ui.alert('⚠️ Change order? ⚠️', 'Are you sure you want to change this order?',ui.ButtonSet.YES_NO)}}} ;
if(response == ui.Button.NO) {e.range.setValue(old)} ;
this is where I am at, everything works great.... as long as a button is pressed, I am hoping there is a way to Auto press "no" after ~20 seconds.

This is not exactly you want.
Because it doesn't ask for yes or no. It just shows a timeout message. But I think it can be modified as per your requirement.
function showTimeoutAlert(header, message, time){
SpreadsheetApp.getUi().showModelessDialog(
HtmlService.createHtmlOutput(
'<div>'+ message + '</div>' +
'<script> \
var a = document.querySelector("div"); \
a.addEventListener("click",()=>{setTimeout(google.script.host.close,'+ time +')}); \
a.click(); \
</script>'
).setHeight(50),
header
);
}
Use it like:
showTimeoutAlert("No serial number(s) found", "Sr. No(s) 2, 3 not found", 2000)
It will show this message for 2 seconds
One can adjust timeout time in milliseconds.

I believe your goal as follows.
You want to automatically run the script as clicking "NO" button after 20 seconds from opening the dialog.
Modification points:
Unfortunately, in the current stage, the count down cannot be achieved with SpreadsheetApp.getUi().alert(). So in your situation, in order to achieve your goal, I would like to propose to use the custom dialog. When the custom dialog is used, Javascript can be used. By this, the count down can be used.
When above points are reflected to a script, it becomes as follows.
Sample script:
Google Apps Script side:
Please copy and paste the following script to Code.gs of the script editor of Spreadsheet.
function processForNo(value) {
// do something
Browser.msgBox(`Clicked NO. Retrueved value is '${value || ""}'.`);
}
function processForYes(value) {
// do something
Browser.msgBox(`Clicked YES. Retrueved value is '${value || ""}'.`);
}
// Please run this function.
function main() {
var value = "ok";
var html = HtmlService.createTemplateFromFile("index");
html.value = value;
SpreadsheetApp.getUi().showModalDialog(html.evaluate().setHeight(100), '⚠️ Change order? ⚠️');
}
HTML & Javascript:
Please copy and paste the following script to index.html of the script editor of Spreadsheet.
Are you sure you want to change this order?
<input type="button" id="yes" value="YES" onclick="google.script.run.withSuccessHandler(google.script.host.close).processForYes()">
<input type="button" id="no" value="NO" onclick="processForNo('')">
<script>
const processForNo = _ => google.script.run.withSuccessHandler(google.script.host.close).processForNo(<?= value ?>);
setTimeout(processForNo, 20000);
</script>
When main() of above script is run, a dialog is opened. When you don't click the buttons, the dialog is closed after 20 seconds, and the process is run as clicking "NO" button. At that time, processForNo is run. Also, the value can be sent when the dialog is opened.
When "YES" button is clicked, processForYes is run.
Testing:
When above script is tested, the following situation is obtained.
Note:
Above script is a sample script for confirming the script. When above script is included in your script, it becomes as follows.
Google Apps Script side
function myFunction() {
// do something. I cannot understand about your whole script. So please add your actual script and function name.
var old = e.oldValue;
var ui = SpreadsheetApp.getUi();
if (old == null) {
} else {
if (old == "NO") {
} else {
if (e.range.getRow() == 3) {
} else {
var html = HtmlService.createTemplateFromFile("index");
html.value = old;
ui.showModalDialog(html.evaluate().setHeight(100), '⚠️ Change order? ⚠️');
}
}
}
}
function processForNo(old) {
// do something
}
function processForYes(value) {
// do something
}
HTML & Javascript side is the same with above sample script.
Although I cannot confirm your function name from your question, from var old = e.oldValue in your script, I thought that you might be using the OnEdit trigger of the simple trigger. If my understanding is correct, when you use above script, please use the installable OnEdit trigger. By this, when the cell is edited, showModalDialog works. Ref
References:
Custom dialogs
Installable Triggers

Related

Cypress Click if item exist

I need a way to easily trigger a click() event only if an element exist on page.
the fact that the element (confirm modal dialog) itself exist is not an issue for my test, but this can stop next steps. so I want to click OK only if the dialog is shown.
I tried something like this, but it didn't work:
cy.get('body').find("button[data-cy=sometag]").then(items => {
if(items.length) {
cy.get('button[data-cy=sometag]').click();
}
});
If you want to test that the modal exists but don't want to fail the test if it doesn't, use a jQuery selector.
const found = Cypress.$('button[data-cy=sometag]').length
Modals are likely to animate on opening, so you you will need to repeat the check a few times, which you can do in a function
function clearModal(selector, timeout = 1000, attempts = 0)
if (attempts > (timeout / 100)) {
return; // modal never opened
}
if (!Cypress.$(selector).length) { // not there yet, try again
cy.wait(100)
clearModal(selector, timeout, ++attempts)
else {
Cypress.$(selector).click() // modal is up, now close it
}
}
clearModal('button[data-cy=sometag]')
If you use the find like this cy.get('body').find("button[data-cy=sometag]") this will fail always whenever the element is not present. Instead you can use the find command inside the If condition and check its length.
cy.get('body').then($body => {
if ($body.find("button[data-cy=sometag]").length > 0) {
cy.get('button[data-cy=sometag]').click();
} else {
//Do something
}
})
Instead of body, you can also use the parent element of the element in question, which you know for sure is visible and present on the page every time.

How can I check with Google Apps Script whether the sidebar opened by "SpreadsheetApp.getUi().showSidebar(html);" is open or not open?

Background: The sidebar cannot be opened with onOpen().
"PropertiesService.getScriptProperties();" should not be used because it is only suitable for one user (possible overlaps). If the sidebar is open, nothing should happen to prevent it from being reloaded, otherwise it should be opened. A global variable could not be overwritten within a function for the next execution.
function sidebar() {
if (? == 'off') {
var html = HtmlService.createHtmlOutputFromFile('sidebar')
.setTitle('Title');
SpreadsheetApp.getUi()
.showSidebar(html);
}
}
With getUserProperties() it works per user per script. A sidebar can be opened with onOpen() by adding a trigger to the respective script for onOpen() at https://script.google.com/home/.
var status = PropertiesService.getUserProperties(); // global variable
function onOpen() {
status.setProperty('sidebar', 'off');
sidebar();
}
function sidebar() {
if (status.getProperty('sidebar') == 'off') {
var html = HtmlService.createHtmlOutputFromFile('sidebar')
.setTitle('Title');
SpreadsheetApp.getUi()
.showSidebar(html);
status.setProperty('sidebar', 'on');
}
}
This is what I found to work in this particular situation. It's not perfect, but it is functional and pretty simple:
.html
window.setInterval(function(){
google.script.run.collectPing();
}, 10000);
.gs
function collectPing() {
CacheService.getDocumentCache().put('sidebar', 'on', 15);
}
While the sidebar is open, it calls the server-side every 10 seconds and sets a property in the cache which lasts for 15 seconds. You can then write a function on the server-side that looks at the cache and does something based on the cache property. I just came up with this, so it is relatively untested, though my first try seems to indicate that it works.

protractor click action relies on ptor.sleep(). How can I resolve correctly?

I'm a newbie trying to not rely so much or at all on using ptor.sleep() calls, especially after the click below. The line below never gets the value (they all return Nan)unless I include the ptor.sleep(1000); call after the click() below.
I've made various attempts to make the array elem to resolve before the results of the list after clicking, wrapping the click in the function, etc, but nothing I've tried works without the sleep calls. Already read up on protractor control flow.
devCountString = parseInt(arr[i]);
Thanks for any insights, maybe something obvious I've missed so that I can remove the ptor.sleep() calls.
my spec:
describe('\n == patch List suite results == \n', function() {
// login already was done in config files, onPrepare function.
var ptor, noFilterCount;
// needed here if we turn ptor.ignoreSynchronization = false;
beforeEach(function() {
ptor = protractor.getInstance();
ptor.ignoreSynchronization = true;
browser.get('https://my.abc.com:3000/fixes');
ptor.sleep(1200);
}); //end beforeEach()
it('11 - verify filter fewer', function() {
var sevStringElm, sevString;
var applicableCount;
ptor.ignoreSynchronization = false;
ptor.sleep(500);
sevStringElm = element(by.css("input.form-control.bf-spinner"));
sevStringElm.clear();
ptor.sleep(500);
sevStringElm.sendKeys( '8' );
ptor.sleep(500);
// click on the "fewer" spinner, wrap the click to wrap the .
var fewerPromise = element(by.css("span.bf-spinner-toggle:nth-child(2)")).click();
ptor.sleep(1000);
// now get the list of clickable elements in each device card. by title
var applicableDevicesElm = element.all(by.css("[title$='Applicable\ Devices']"));
applicableDevicesElm.getText().then(function(arr) {
console.log("arr.length= "+arr.length);
for (var i = 0; i < arr.length; i++) {
devCountString = parseInt(arr[i]);
expect(devCountString).toBeLessThan( 9 );
};
});
});
Everytime an action goes to the webdriver, Protractor will put that into the flow queue as shown in the documentation. As a result, when you get to inspect your elements after the click, the queue should have resolved the dependencies and have your state ready for the finder. In any case, even if you don't want to have the implicit wrapping that Protractor does on its actions (which are always asyc), you can put a .then(function(){}) after the click and put the post click logic in that anonymous calback function.
On a side note, you should have to use ptor anymore. Use browser instead that mixes in the protractor instance capabilities. Example: browser.sleep(1000)

Slickgrid - One-click checkboxes?

When I create a checkbox column (through use of formatters/editors) in Slickgrid, I've noticed that it takes two clicks to interact with it (one to focus the cell, and one to interact with the checkbox). (Which makes perfect sense)
However, I've noticed that I am able to interact with the checkbox selectors plugin (for selecting multiple rows) with one click. Is there any way I can make ALL of my checkboxes behave this way?
For futher readers I solved this problem by modifing the grid data itself on click event. Setting boolean value to opposite and then the formatter will display clicked or unclicked checkbox.
grid.onClick.subscribe (function (e, args)
{
if ($(e.target).is(':checkbox') && options['editable'])
{
var column = args.grid.getColumns()[args.cell];
if (column['editable'] == false || column['autoEdit'] == false)
return;
data[args.row][column.field] = !data[args.row][column.field];
}
});
function CheckboxFormatter (row, cell, value, columnDef, dataContext)
{
if (value)
return '<input type="checkbox" name="" value="'+ value +'" checked />';
else
return '<input type="checkbox" name="" value="' + value + '" />';
}
Hope it helps.
The way I have done it is pretty straight forward.
First step is you have to disable the editor handler for your checkbox.
In my project it looks something like this. I have a slickgridhelper.js to register plugins and work with them.
function attachPluginsToColumns(columns) {
$.each(columns, function (index, column) {
if (column.mandatory) {
column.validator = requiredFieldValidator;
}
if (column.editable) {
if (column.type == "text" && column.autocomplete) {
column.editor = Slick.Editors.Auto;
}
else if (column.type == "checkbox") {
//Editor has been diasbled.
//column.editor = Slick.Editors.Checkbox;
column.formatter = Slick.Formatters.Checkmark;
}
}
});
Next step is to register an onClick event handler in your custom js page which you are developing.
grid.onClick.subscribe(function (e, args) {
var row = args.grid.getData().getItems()[args.row];
var column = args.grid.getColumns()[args.cell];
if (column.editable && column.type == "checkbox") {
row[column.field] = !row[column.field];
refreshGrid(grid);
}
});
Now a single click is suffice to change the value of your checkbox and persist it.
Register a handler for the "onClick" event and make the changes to the data there.
See http://mleibman.github.com/SlickGrid/examples/example7-events.html
grid.onClick.subscribe(function(e, args) {
var checkbox = $(e.target);
// do stuff
});
The only way I found solving it is by editing the slick.checkboxselectcolumn.js plugin. I liked the subscribe method, but it haven't attached to me any listener to the radio buttons.
So what I did is to edit the functions handleClick(e, args) & handleHeaderClick(e, args).
I added function calls, and in my js file I just did what I wanted with it.
function handleClick(e, args) {
if (_grid.getColumns()[args.cell].id === _options.columnId && $(e.target).is(":checkbox")) {
......
//my custom line
callCustonCheckboxListener();
......
}
}
function handleHeaderClick(e, args) {
if (args.column.id == _options.columnId && $(e.target).is(":checkbox")) {
...
var isETargetChecked = $(e.target).is(":checked");
if (isETargetChecked) {
...
callCustonHeaderToggler(isETargetChecked);
} else {
...
callCustonHeaderToggler(isETargetChecked);
}
...
}
}
Code
pastebin.com/22snHdrw
Search for my username in the comments
I used the onBeforeEditCell event to achieve this for my boolean field 'can_transmit'
Basically capture an edit cell click on the column you want, make the change yourself, then return false to stop the cell edit event.
grid.onBeforeEditCell.subscribe(function(row, cell) {
if (grid.getColumns()[cell.cell].id == 'can_transmit') {
if (data[cell.row].can_transmit) {
data[cell.row].can_transmit = false;
}
else {
data[cell.row].can_transmit = true;
}
grid.updateRow(cell.row);
grid.invalidate();
return false;
}
This works for me. However, if you're using the DataView feature (e.g. filtering), there's additional work to update the dataview with this change. I haven't figured out how to do that yet...
I managed to get a single click editor working rather hackishly with DataView by calling
setTimeout(function(){ $("theCheckBox").click(); },0);
in my CheckBoxCellEditor function, and calling Slick.GlobalEditorLock.commitCurrentEdit(); when the CheckBoxCellEditor created checkbox is clicked (by that setTimeout).
The problem is that the CheckBoxCellFormatter checkbox is clicked, then that event spawns the CheckBoxCellEditor code, which replaces the checkbox with a new one. If you simply call jquery's .click() on that selector, you'll fire the CheckBoxCellEditor event again due because slickgrid hasn't unbound the handler that got you there in the first place. The setTimeout fires the click after that handler is removed (I was worried about timing issues, but I was unable to produce any in any browser).
Sorry I couldn't provide any example code, the code I have is to implementation specific to be useful as a general solution.

Form validation on Facebook tab

I am using static FBML but I am having trouble debugging a form validation problem. I get the dialog which to me seems like it should return false, but the form submits anyway. I am using Firebug and I see a brief message in Red that I have no chance to read. I appreciate the help :-)
var txt ='Enter Zipcode';
//...
function setError(){
var obj=document.getElementById('mapsearch');
obj.setValue(txt);
obj.setStyle('color', '#FF0000');
}
function valform(){
var obj=document.getElementById('mapsearch');
var val = obj.getValue();
if(val!='' && !isNaN(val) && val.length>2 ){
return true;
} else {
setError();
(new Dialog()).showMessage('Zip Required', 'Please enter your zip code.');
return false;
}
}
//...
Try the "Persist" button if the Firebug/javascript error message in Firebug disappears too quickly. This way all messages are kept between page loads until you click "Clear".

Resources