Create multiple links to websites in main menu of Google Sheets - if-statement

Well, thanks in advance for those who will help me to solve this one.
What I am trying to do is to create clickable itens in the main menu of Google Sheets. The step of creating multiple drop list items is already overcome, using this script to create menu itens:
const onOpen = () => {
const ui = SpreadsheetApp.getUi();
const parentMenu = ui.createMenu('Partners');
parentMenu.addItem('Thebest50s','openWebsite');
parentMenu.addItem('The20best','openWebsite');
parentMenu.addToUi();
};
Used this HTML as a reference:
<!DOCTYPE html>
<html>
<body>
Click here to open the webpage.
</body>
<script>
var windowReference = window.open('<?= url; ?>', '_blank');
if (windowReference !== null) {
google.script.host.close();
}
</script>
</html>
And this script to open the first item of the menu when the client click in it:
const openWebsite = () => {
const htmlTemplate = HtmlService.createTemplateFromFile('url.html');
htmlTemplate.url = 'https://www.theworlds50best.com/list/1-50';
const htmlOutput = htmlTemplate.evaluate().setHeight(50).setWidth(200);
const ui = SpreadsheetApp.getUi();
ui.showModelessDialog(htmlOutput, 'Thebest50s');
Utilities.sleep(2000)
But obviously I didn't open the second item when I click in it.
I try to put some conditions, but it didn't help. Could someone help to solve this: when click in The20best items it opens https://www.getbento.com/blog/best-restaurant-websites-design/

Try using this script:
function onOpen() {
SpreadsheetApp.getUi().createMenu("Partners")
.addItem("Thebest50s", "openBest50")
.addItem("The20best", "openBest20")
.addToUi();
}
/**
* Run when "Thebest50s" is selected from the "Partners" menu is clicked.
*
*/
function openBest50(){
openUrl("https://www.theworlds50best.com/list/1-50'")
};
/**
* Run when "The20best" is run from the "Partners" menu or when the red YouTube button is clicked.
*/
function openBest20(){
openUrl("https://www.getbento.com/blog/best-restaurant-websites-design/")
}
function openUrl(url){
const blob = `
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
<div id="blocked" hidden>
<p>Go to link! \>\></p>
<p>You may have popups blocked for Google Workspace.</p>
<p>You can always remove the popup block for next time. 👍</p>
<button onclick="google.script.host.close()">Close</button>
</div>
<script>
const urlLinked = window.open("${url}");
if(urlLinked){
google.script.host.close()
}else{
document.getElementById("blocked").hidden = false;
}
</script>
</body>
</html>
`
const html = HtmlService.createHtmlOutput(blob)
.setWidth(400)
.setHeight(200);
const ui = SpreadsheetApp.getUi();
ui.showModalDialog(html,"Link")
};
This script should show create a custom menu with 2 different options: TheBest50s and The20Best. You may want to update the menu information as you desire. The problem with your previous script is that you never set the URL for The20Best therefore clicking on it will not redirect the user anywhere.

Related

Power Bi and WebBrowser control

It is possible to render a power bi report in a windows form web browser control? I created an html file and added to navigate method but is not working. Also I added the html content to the documenttext property and is not working.
I'm using the embed for customer.. approach but I only get a blank page. This is the code that I pass to the webbrowser control. Do you have a sample using the windows forms project?
<!DOCTYPE html>
<html lang='en' xmlns='http://www.w3.org/1999/xhtml'>
<head>
<meta charset='utf-8' />
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js' referrerpolicy='no-referrer'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/powerbi-client/2.19.1/powerbi.min.js' integrity='sha512-JHwXCdcrWLbZo78KFRzEdGcFJX1DRR+gj/ufcoAVWNRrXCxUWj2W2Hxnw61nFfzfWAdWchR9FQcOFjCNcSJmbA==' crossorigin='anonymous' referrerpolicy='no-referrer'></script>
</head>
<body>
<div id='embedContainer'></div>
<script type="text/javascript">
const reportContainer = $('#embedContainer')[0];
const accessToken = 'token.....';
const embedUrl = 'https://xxx.powerbi.com/reportEmbed?reportId=0b0fe232.....';
const embedReportId = '0b0fe232.....';
const tokenExpiry = '5/20/2022 5:42:13 PM';
const models = window['powerbi-client'].models;
const config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl,
id: embedReportId,
permissions: models.Permissions.All,
settings:
{
filterPaneEnabled: true,
navContentPaneEnabled: true
}
};
const report = powerbi.embed(reportContainer, config);
</script>
</body>
</html>
Thanks,
Ev
Yes. There are a number of approaches you can consider.
Power BI Secure Embedding just uses an IFrame and the desktop user will need to authenticate to Power BI. Minimally generate the embedding link from Power BI
and embed it in an a static HTML page like this:
<html>
<iframe title="Some Report"
style="position: absolute; height: 100%; width: 100%; border: none"
src="https://xxx.powerbi.com/reportEmbed?reportId=d12ecc27-a855-4b27-9..."
frameborder="0"
allowFullScreen="true">
</iframe>
</html>
Or you can build and register full web app to do embedding using either the Embed For Your Customers, or the Embed For Your Organization workflow. This adds a javascript API to control and interact with the embedded reports from your hosting application.

Django with Vue, detect form validation error

I have a Django ModelForm which is displayed in the template by using using crispy forms. After the user fills out the fields and presses a Submit button, an email is sent at the backend using Django's core send_email.
The problem is that the call to send_email is synchronous, so the user has to wait for the next page to load (success/failure page) but in this time the user might press the Submit button again and this generates multiple POSTs, making multiple emails.
I want to use Vue.js to make the button inactive once the user presses it but only if it passes Django's form validation. Is there a way to detect this?
Add to your button :disabled="!readyToSend" where readyToSend can be returned by your data function or a computed propoerty.
Before submitting the form set this variable to false, afater receiving data from your API, reset it to true.
In the following example I've choosen to make readyToSend a computed proporty where it will return true if the form is valid and if the process is not waiting for the API response.
The complete Code Pen example is here
html file :
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>example</title>
</head>
<body>
<div id="app">
<h2>{{ message }}</h2>
<form #submit.prevent>
<input type="text" v-model="dataToSend" placeholder="Something to send">
<button type="button" :disabled="!readyToSend" #click="send">Send</button>
</form>
</div>
</body>
</html>
javascript:
var vm = new Vue({
el: '#app',
data: function(){
return {
message: "please enter your message and click on send.",
dataToSend: "",
sentAndWaiting: false,
}
},
methods:{
send: async function(){
this.sentAndWaiting = true;
// Send Data Here
this.message = "sending....";
try{
let response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
let jsonResponse = await response.json();
}
catch(e){
this.message = e.message;
}
// reponse received ... do Something with it
this.reponseReceived();
},
reponseReceived: function(){
this.sentAndWaiting = false;
this.message = "Ok. Got The response.";
}
},
computed:{
readyToSend: function(){
return this.dataToSend.length > 0 && !this.sentAndWaiting;
}
},
});
in my browser I had to test this by going to the developper tools and limit my internet connexion to the GPRS and disabling cache:
Screenshot DevTools

Removing loading screen and spinner after all contents of the window have loaded but before iframes have finished loading

I am using a loading screen with a spinner that is displayed before all contents in the window have loaded. It works well on all pages and the window loads very fast on webpages with less content but on one of my pages, I am loading many iframes that embed youtube videos. $(window).on('load', function(){}); doesn't trigger until all contents have loaded, including iframes. That means that loading takes a long time and the loading screen with the spinner is shown long after the browser has finished loading the HTML, CSS, JS, and all images. I want to use skeleton loading for the iframes after the HTML, CSS, JS, and all images have loaded to cut down on perceived load time. Is there a way to tell that the rest of the window has fully loaded but the iframes are still loading? This is what I am currently doing to remove the loading screen with the spinner:
<html>
<head>
</head>
<div class="spinner-wrapper">
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<body>
{% for video in range(videos|length) %}
<iframe class="yvideo" src="{{ "https://www.youtube.com/embed/%s" + videos[video]}.get("url") }}"></iframe>
{% endfor %}
<script type=module src="{{ url_for('static', filename='js/video.js') }}"></script>
</body>
</html>
videos.js:
$(window).on('load', function() {
preloaderFadeOutTime = 300;
function hidePreloader() {
var preloader = $('.spinner-wrapper');
preloader.fadeOut(preloaderFadeOutTime);
}
hidePreloader();
});
There can be multiple ways to solve this issue:
One simple approach can be to keep source of iframes empty initially and dynamically set source of iframes upon window.load.
Here sample code:
<script>
$(window).on('load', function() {
document.getElementById('myIframe').src = "your URL";
document.getElementById('myIframe2').src = "your URL";
preloaderFadeOutTime = 300;
function hidePreloader() {
var preloader = $('.spinner-wrapper');
preloader.fadeOut(preloaderFadeOutTime);
}
hidePreloader();
});
</script>
<iframe id="myIframe" src="" ></iframe>
<iframe id="myIframe2" src="" ></iframe>
EDIT:
If you cannot change the video.js file but can create your own js files which can interact with html on the page then do below in your custom js file:
//your external js
// first get collection of your iframes by class
var listOfIframes = document.getElementsByClassName("yvideo");
for (let item of listOfIframes) {
item.src = ""; // set them to empty.
}
window.addEventListener("load", function() {
//once page is loaded then populate the source with your json file.
for (let item of listOfIframes) {
item.src = "URLs from JSON";
}
});
Second approach:
Instead of calling hidePreloader() only at window.load. You can also check for the rest of the items in your page that if they are loaded or not. Once they are loaded, then you can use call hidePreloader()

How to hide "Page" and "Filter" while embedding a Power BI report using an iFrame

I am trying to embed a Power BI report in my web page using an iframe, but it shows page name and side right filter with the report in the web page, can we hide both page name and filter from the report?
You can configure the settings for the report. Set the below flags to false in order to achieve what you want in the settings.
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: false
}
You can read about it here:
https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details
As mentioned by the other answer, you can try passing in these arguments if you are using the PowerBI JavaScript API: https://github.com/microsoft/PowerBI-JavaScript
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: false
}
Docs:
https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details
Failing that, you can try to manipulate the DOM of the iframe you're using like so:
<!DOCTYPE html>
<html>
<body>
<iframe id="myframe" src="demo_iframe.htm"></iframe>
<p>Click the button to change the background color of the document contained in the iframe.</p>
<p id="demo"></p>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction() {
var x = document.getElementById("myframe");
var y = (x.contentWindow || x.contentDocument);
if (y.document) y = y.document;
y.body.style.backgroundColor = "red";
}
</script>
</body>
</html>
You can see a demo if it here:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_iframe_contentdocument
and an explanation on how this works here:
https://www.w3schools.com/jsref/prop_frame_contentdocument.asp

collection-repeat and ion-option-button issues (again!)

I am currently writing an application using socket.io and ionic. I have to handle a list of 6000 people so I've decide to use collection-repeat and swipe + ion-option-button to verify items (remove then from the list)
The names on the list can be removed and the changes will be broadcasted to the rest of apps using sockets so everyone will have their own list updated in real-time
But if If the list change, each row is assigned new data but the html stays the same, including the state of the swiped button!
Here is a screen recording of the bug: https://youtu.be/15oZj7G1DQ0
You can see the list shrinking because another user is removing items from the list and broadcasting to me through websockets, but the button doesn't move along with the item and just stays in the same place.
The problem doesn't happen with ng-repeat but I can't use ng-repeat for this.
And I can't use $ionicListDelegate.closeOptionButtons() to go around the problem because it can be really annoying for the users.
There is any possible solution for this?
resumed code sample:
1) people controller
$rootScope.verify = function(){
this.person.verified = true;
//broadcast to main controller
$rootScope.$broadcast('verify', this.person)
}
2) Main Controller (aka socket controller)
$rootScope.$on('verify', function(e, person) {
//send to socket server
socket.emit('event:verify', person);
});
//incoming data from the socket server
socket.on('event:incoming',function(personData){
var person = $filter('filter')($scope.people, {id: personData.id}, true)[0];
var key = $scope.people.indexOf(person);
$scope.people[key].verified = personData.verified;
});
so if you look at this example: http://play.ionic.io/app/a8d986cdaf19
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<link href="http://code.ionicframework.com/1.0.0/css/ionic.min.css" rel="stylesheet">
<script src="http://code.ionicframework.com/1.0.0/js/ionic.bundle.js"></script>
</head>
<body ng-app="app">
<ion-pane>
<ion-header-bar class="bar-stable">
<h1 class="title">Awesome App</h1>
</ion-header-bar>
<ion-content class="padding">
<ion-list>
<ion-item>
I love kittens!
<ion-option-button ng-if="item" class="button-positive">Share</ion-option-button>
<ion-option-button class="button-assertive">Edit</ion-option-button>
</ion-item>
</ion-list>
<ion-toggle ng-model="item">
Show Delete?
</ion-toggle>
</ion-content>
</ion-pane>
</body>
</html>
You can use ng-if to show or hide a optoin button, so you can broadcast a event when a item is removed and hide the option button with a variable that you can toggle based on the event.
$scope.$emit('objectRemoved');
and then:
$scope.$on('objectedRemoved', function(){
$scope.variableToControlVerifyButton = false;
})
if you post your code I may be able to help more but I hope you get the general idea.