Google Apps Script DialogBox show from clienthandler [closed] - event-handling

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I am trying to create an 'Are You Sure' type dialog using a DialogBox. So when someone clicks a button, a popup shows with yes/no buttons for the user to confirm they wish to proceed with the action.
I have figured most of it out, however I can't figure out how to make it show without calling back to a server handler.
I tried using the show() command with a Client Handler, but it doesn't work. I tried using setVisibility() also, but couldn't get this working either.
I don't want to have to make a round trip just to show the dialog box for the obvious user experience reasons.
Does anyone have any suggestions?
Thanks in advance
Chris

Here is a small snippet i have created for just this reason. It does however use a server handler...
function MsgBox(message, title, id, buttons, handler, modal, autoHide){
this.message=message;
this.title=title;
this.id=id;
this.buttons=buttons;
this.handler=handler;
this.modal=(modal)?true:false;//Default is false
this.autoHide=(autoHide)?new Boolean(autoHide):true;//Default is true
this.position={};
this.position.top=100;
this.position.left=550;
this.position.width=400;
this.button={};
this.button.ok={name:"Ok",id:"OK_BTN"};
this.button.yes={name:"Yes",id:"YES_BTN"};
this.button.no={name:"No",id:"NO_BTN"};
this.button.cancel={name:"Cancel",id:"CANCEL_BTN"};
this.button.retry={name:"Retry",id:"RETRY_BTN"};
this.addButton=function(btn){
try{
if(this.buttons==undefined){this.buttons=[];}
if(typeof btn=="string"){btn=this.button[btn.toLowerCase()];}//If a string, convert to the intended object
if(btn.name==undefined){return this;}//Check if we've actualy got one of the buttons by checking one of it's properties. Exit if not.
this.buttons.push(btn);
}catch(err){
Logger.log(err.message);
}
return this;
};
this.show=function(e, app){
if(app==undefined){app=UiApp.getActiveApplication();}
if(this.buttons==undefined){this.buttons=[this.button.ok];}//The default is one 'Ok' button
var dialog=app.createDialogBox(true,true).setId(this.id).setText(this.title);
dialog.setPopupPosition(this.position.left,this.position.top);
dialog.setGlassEnabled(this.modal);
dialog.setAutoHideEnabled(this.autoHide);
var basePanel=app.createVerticalPanel().setWidth(this.position.width+"");
basePanel.add(app.createLabel(this.message).setWordWrap(true).setStyleAttribute("padding", "10px"));//Add message
var buttonPanel=app.createHorizontalPanel().setId("ButtonPanel");
basePanel.add(buttonPanel.setStyleAttribute("display", "block").setStyleAttribute("margin-left", "auto").setStyleAttribute("margin-right", "auto"));
var btnHandler=app.createServerHandler("msgBox_close").addCallbackElement(buttonPanel);
for(var i=0;i<this.buttons.length;i++){
var btn=app.createButton(this.buttons[i].name, btnHandler).setId(this.buttons[i].id).setTag(this.id);
if(this.handler!=undefined){btn.addClickHandler(this.handler);}
buttonPanel.add(btn);
}
dialog.add(basePanel).show();
return app;
};
}
function msgBox_close(e, app){
if(app==undefined){app=UiApp.getActiveApplication();}
var dialogId=e.parameter[e.parameter.source+"_tag"];
app.getElementById(dialogId).hide();
return app;
}
Here is a smal example how to use it.
var msgBox=new MsgBox("Testing 123...", "This is a test", "MyMsgBox");
msgBox.show(e, app);
By using the '_tag' parameter to reference its own ID you make a clean roundtrip with little hassle.
You can add standard buttons by calling the .addButton() function.
Example:
msgBox.addButton("yes").addButton("no");
By passing your own handler, you can call your own functions.
Example:
function myOwnHandler(e, app){
if(app==undefined){app=UiApp.getActiveApplication();}
if(e.parameter.source.indexOf("YES_BTN")!=-1){
}
return app;
}

Related

Detecting if browser extension popup is running on a tab that has content script

There a few similar questions, but none of them have really gotten at what I'm asking.
I have a browser action popup. In the popup, I want to display settings if you're on a page where the content script has been injected (i.e., any page that matches the matches key within the content_scripts in the `manifest).
If I'm on a page that doesn't match the content_scripts matches pattern (and so wasn't injected), I just want to display a generic message "this plugin activates when you're on so-and-so sites".
What is the cleanest way to do it, without adding any unnecessary permissions?
It seems like one option is sending a message to a content script in the active tab, and seeing if I get a reply, but that seems really.. hacky. I should be able to know just based on a regex if I'm on one of the domains that matches my content script.
I'm looking for something that works in both manifest v2 and v3, btw.
TL;DR;
What's the simplest way to display a "you're on a page that matches your content_script" or "you're not on a page that matches your content_script" in a browser_action popup?
I build chrome extensions full time for an agency and have had projects where I needed to do exactly what you're asking.
The solution can be implemented w/o any permissions whatsoever. I built mine locally with an empty array for permissions. (for mv3)
for popup.html just create 2 divs and have them default to display none.
<div id="unsupported" style="display: none;">Ooops! This is not a supported site.</div>
<div id="supported" style="display: none;">Wohoo! This is a supported site!!!!!</div>
for your script.js, wait till the popup loads then query the active tab in the current window and get that tab's ID to send a message directly to it. If the tab is supported with a content script, it will send a true response (see last code snippet). If it wasn't supported, it will be an 'undefined' response.
async function setUI() {
let tabData = await chrome.tabs.query({ active: true, currentWindow: true })
let tabId = tabData[0].id // tabs.query returns an array, but we filtered to active tab within current window which yields only 1 object in the array
chrome.tabs.sendMessage(tabId, {
'message': 'isSupported'
}, (response) => {
console.log(response)
// response will be true if the message was successfuly sent to the tab and "undefined" if the message was never received (i.e. not supported w/ your content script)
if (response) return showSupportedHTML()
// else
showUnsupportedHTML()
})
}
function showSupportedHTML() {
document.querySelector('#supported').style['display'] = ''
}
function showUnsupportedHTML() {
document.querySelector('#unsupported').style['display'] = ''
}
window.addEventListener('DOMContentLoaded', () => {
setUI()
})
Lastly, in your content script, add a message listener to receive the message 'isSupported' that comes in from your content script. If the content script receives that message, have it send a response back with 'true'.
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.message == 'isSupported') {
console.log('run')
sendResponse(true)
}
})
Now, this of course only works for manifest v3 because as far as I know you can't use chrome.tabs.query for mv2. However, I recommend this solution as I've implemented pretty much this exact same code in other projects for clients and it's never had any issues.
I could look into a solution for mv2, though using the "activeTab" permission would be the right way to do it, I believe. Now, if you really don't want to go that route then you could implement a rather hacky solution. For example, you could use window 'focus' and window 'blur' events to see when a user has entered or left a tab. Then set a local storage variable every time a user enters / leaves a supported page. The order of operations for blur and focus is always blur => focus. So, when the blur event occurs you set a local storage variable to false. However, if you leave a supported tab for another supported tab then the 'focus' event will trigger immediately afterwards so you can set that same storage variable back to true.
Now, your content script will load after the tab has been focused so you'll need to add a function for when the page loads. You can run something like document.hidden and if that returns true, do nothing because the user already left this tab. If it returns false, then the user is still on the tab and you can set your local storage variable to true.
When the user opens the popup, you'll check that local storage variable and if its true or false, you can set the UI accordingly.
Let me know if the mv2 solution made sense or sounds too hacky. Happy to look into it more! :)
edit: Here is the code for mv2, I tested it and it does work and without any permissions, other than storage which is not an invasive permission.
Script.js for the mv2 popup:
async function setUI() {
chrome.storage.local.get(['isSupported'], function (response) {
console.log(response['isSupported'])
// response will be true if the message was successfuly sent to the tab and "undefined" if the message was never received (i.e. not supported w/ your content script)
if (response['isSupported']) return showSupportedHTML()
// else
showUnsupportedHTML()
})
}
function showSupportedHTML() {
document.querySelector('#supported').style['display'] = ''
}
function showUnsupportedHTML() {
document.querySelector('#unsupported').style['display'] = ''
}
window.addEventListener('DOMContentLoaded', () => {
setUI()
})
code for the content script in mv2:
if (!document.hidden) chrome.storage.local.set({'isSupported': true})
window.addEventListener('blur', () => {
console.log('left site')
chrome.storage.local.set({'isSupported': false})
})
window.addEventListener('focus', () => {
console.log('entered site')
chrome.storage.local.set({'isSupported': true})
})
Let me know if you have any additional questions.
Disclaimer: I have no prior browser extension development experience and am just going by the docs. I might be spouting nonsense or giving an answer that is plainly against your requirements, but that would be out of ignorance and not malicious intent. If you find my answer problematic, comment, or cast a vote and move on.
According to MDN, the activeTab permission allows to read the active tab's Tab.url property. One solution could be to request that permission, and then use that API to get the active tab's URL, and then use the same regex from the manifest.json's matches property to test for a match, and then use that information to modify your extension's browser_action UI.
You should be able to read the matches property from the manifest file via the .runtime.getManifest() API. MDN docs, chrome docs.
Snippet to get active tab in a background script: tabs.query({active: true}). (link to MDN docs). A content script should instead use tabs.getCurrent and the Tab.active property of the resolved result.
If you don't want to request the activeTab permission, what you're suggesting with the message-passing between the browser_action scripts and the content scripts might be the right way to go, but I don't know for a fact. The tabs.onActivated event would probably be useful with this approach. Note that to send a message from a background script to a content script, you need to use tabs.sendMessage (MDN docs, chrome docs) instead of runtime.sendMessage.
Another possible (maybe?) approach would be to listen for the tab change in the content script and then send the notification message from the content script to the extension's background scripts via the onfocus event (or similar events), and runtime.sendMessage.
If you go with a messaging-related approach, you might want to put a condition in the content script to only do messaging if the content script is in the top frame of the tab (Ie. iframes don't do messaging), since only one frame of the tab really needs to do this kind of messaging when the active tab changes, and content scripts can be applied to all frames in a browsing context.
Of these possible solutions I can think of, I don't know which is best for you, since you want both minimal permission requirements and a simple/clean approach, and each seems to be a tradeoff.

How to update data without wiping all other data in Firestore with Flutter? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am working on an app and I am trying to update a bool to true, I tried updateData() but it just wipes the whole documents' field, so if anyone knows a better way please ..
You can use setData() function instead of add() method.
void createRecord() async {
await databaseReference.collection("books")
.document("1")
.setData({
'title': 'Flutter',
'description': 'Dart'
},merge=true);// setData sets the data of a document, if it does not exists, then it creates a document with the specified name
}

how to disable pasting on google form?

i want to create a google form that i dont want people answer the questions by pasting from somewhere else, I want them to type their answers.
How can I do this?
I have tried to add js codes to google script but it didn't work.
It's not worh to prevent pasting because it will never be 100% effective, users can tweak prevention and do what they want.
But you can try using javascript.
This will prevent all inputs in your form:
let input = document.querySelector('input');
input.addEventListener('paste', (e) => {
e.preventDefault(); // This is what prevents pasting.
});
And this one will prevent only on an input that is specified by it's ID:
window.onload = function (){
var input = document.getElementById('inputId');
input.onpaste = functino(e){
e.preventDefault();
}
}
Update based on your comment
Here is a complete tutorial on how to create a google form and add scripts to it. It's not the exact same problem, but it's a clue.

Is it possible to force a copy of a protected Google doc? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 4 years ago.
Improve this question
Google docs can “lock” a page so that it’s impossible to copy from its text. This seems wrong to me; shouldn't a computer’s ability to copy and paste be intrinsic? I can’t understand how a webpage can “overstep” its authority and prevent my computer from doing something totally natural. It seems that if I can be served and display text that I should be able to copy it.
How does this webpage prevent my machine from copying?
Here is how to copy (or print) the protected google sheet values.
NOTE: With this technique you can copy the cells from each sheet; it's not possible to duplicate the spreadsheet file itself. Formatting is preserved but formulas are not.
Change the URL to:
https://docs.google.com/spreadsheets/u/1/d/***[document id]***/preview
The document ID is the random string found in the google sheet URL that is normally 40 to 45 characters long.
For each sheet, type Ctrl+A, Ctrl+C
Paste the cells into another spreadsheet. Formatting
As of the 10th of May, 2018, disabling JavaScript will not load the document at all, and changing the 'edit' to 'preview' also no longer works.
I have found that if you click on the three dots and go to:
More Tools > Developer Tools and then click on console, and type in 'document.body.innerText', it loads the entire document as a text file, so that you can copy to your heart's content.
Disable javascript in with developer tools, right click the page, click 'print', change the print destination from your printer to 'save as pdf', and you've got it.
I tried the other options and none worked for me - then, tried downloading webpage and saving link. Re-opened from docs, and then I was able to download as PDF.
EDIT: This doesn't work anymore
I've found out how they're disabling copying, so I'm turning my comment into an answer.
Here's the script that runs on the page that prevents copying:
function rtcScript() {
document.oncontextmenu = null;
document.onselectstart = null;
document.onmousedown = null;
document.onclick = null;
document.oncopy = null;
document.oncut = null;
var elements = document.getElementsByTagName('*');
for (var i = 0; i < elements.length; i++) {
elements[i].oncontextmenu = null;
elements[i].onselectstart = null;
elements[i].onmousedown = null;
elements[i].oncopy = null;
elements[i].oncut = null;
}
function preventShareThis() {
document.getSelection = window.getSelection = function() {
return {isCollapsed: true};
}
}
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].src.indexOf('w.sharethis.com') > -1) {
preventShareThis();
}
}
if (typeof Tynt != 'undefined') {
Tynt = null;
}
}
rtcScript();
setInterval(rtcScript, 2000);
Notice that it's setting every element to not be copyable, selectable, or cuttable, as well as disabling the context menus. This is trivial to bypass by disabling scripts on the page. See this question for how to do it on Chrome. I've tested this myself - if you disable JavaScript via that method while viewing the locked document, you can immediately begin selecting and copying the text with no issues.

Protractor + ionicPopup

Has anyone succeeded in using Protractor to detect an ionicPopup alert?
I've tried all the workarounds suggested here but no luck.
I need Protractor to detect the alert and check the text in the alert.
Here's the class I wrote to test that the popup exists and to ensure the text is correct in the header and body:
var TestUtilities = function(){
this.popup = element(by.css('.popup-container.popup-showing.active'));
//Tests to see if $ionicPopup.alert exists
this.popupShouldExist = function() {
expect(this.popup.isDisplayed()).toBeTruthy();
};
//Tests to see if $ionicPopup.alert contains the text provided in the argument exists in the header
this.popupContainsHeaderText = function (text) {
this.popupShouldExist();
expect(this.popup.element(by.css('.popup-head')).getText()).toMatch(text);
};
//Tests to see if $ionicPopup.alert contains the text provided in the argument exists in the body
this.popupContainsText = function (text) {
this.popupShouldExist();
expect(this.popup.element(by.css('.popup-body')).getText()).toMatch(text);
};
};
module.exports=TestUtilities;
Also check out this site for more on testing Ionic in protractor it talks about how to check to see if the popup exists: http://gonehybrid.com/how-to-write-automated-tests-for-your-ionic-app-part-3/
I've tested Ionic popups successfully by setting the popup variable as follows:
var popup = element(by.css('.popup-container.popup-showing.active'));
And in the test:
expect(popup.isDisplayed()).toBeTruthy();
Ionic Popups are just made of DOM elements, so you should be able to use normal locators to find/test them. Because they're not made of alerts, the workarounds in the issue you linked to are probably not useful.
I got it - I saw a lot of issues out there trying to do it in very complex ways, but in the end I tried this and it turns out to be this simple.
Inspect your element and find its ng-repeat value, then
var button = element(by.repeater('button in buttons')).getText()
You also need to have the browser sit out somehow for a couple seconds so it doesn't resolve to the tests while the ionic popup isn't actually there.
For that, browser.sleep(3000);
That's it! However, getting the other button in there is proving to be a little problem. var button = element(by.repeater('button in buttons')).get(0) or .get(1) return undefined is not a function.
Please accept the answer if you like it! If I figure out how to get the other button, I'll post it here.