I'm trying to make a button to download multiple images in a Blazor webassembly .NET 6 app.
So I've made a button :
<button class="btn icon-download" #onclick=DownloadImages></button>
And my method :
private async Task DownloadImages()
{
int i = 0;
foreach (var p in Pictures)
{
// TODO : needs to take the same extension
await jsRuntime.InvokeVoidAsync("downloadFromUrl", p.Url, $"picture-{i++:00}.jpeg");
}
}
Which call the following javascript function :
function downloadFromUrl(url, filename) {
// Create the <a> element and click on it
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.target = "_self";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
console.log(url, ' downloaded to ', filename);
}
I have 2 issues :
First, when I click on the button, all the downloads are cancelled, except the last one
=> Do I need to wait the download finished ? How could I do that in Javascript ?
Second, once downloaded, the image name doesn't change and keeps the name from the URL. How can I rename it when saving in Download user folder ?
Related
I am trying to use showLoadingIndicator : true in my manifest file and as soon as I load the MicrosoftTeams.js file in my _host.cshtml file I call the javascript to notify success. But this breaks the config Tab. When I search for the item and select the result and click on save it throws error saying tabsettings can not be saved. But if I click on save second time , it works.:
_host.cshtml
<script src="https://res.cdn.office.net/teams-js/2.5.0/js/MicrosoftTeams.min.js"
integrity="sha384-0lOzlvRkoNWAcLkbUTuao6TaDa7zI7v+q2PUAm3lrMxUp43PFwf2kaQu7FYT9fjS"
crossorigin="anonymous"></script>
<script src="~/js/utils.js"></script>
utils.js:
function AppLoaded() {
microsoftTeams.app.initialize().then(() => {
microsoftTeams.app.notifySuccess();
console.log("app loaded");
});
}
AppLoaded();
config.cshtml have:
private async void SetSelectedResult(SearchModel selectedItem)
{
_selectedItem = selectedItem;
if (_selectedItem != null)
{
var settings = new TeamsInstanceSettings
{
SuggestedDisplayName = _selectedItem.Description,
EntityId = _selectedItem.ID.ToString(),
ContentUrl = contenturl",
WebsiteUrl = websiteurl",
RemoveUrl = removeUrl"
};
await MicrosoftTeams.InitializeAsync();
await MicrosoftTeams.RegisterOnSaveHandlerAsync(settings);
}
} ```
You only need to call microsoftTeams.app.notifySuccess(); in the -actual- tab, not in the config panel. Add a switch in your code somehow (based on page name, or a setting, or however you decide to do it) to only call that from in the main tab.
Update: You are also missing the call to notifyAppLoaded, which is even more important that notifySuccess. See in this document, that you actually need to call notifyAppLoaded to 'hide loading indicator'.
How can I create a share button, and also get count for each post shared?
In your Blade file that outputs the article, you can output a button. this contains a hidden textarea as a child element. With JS you can put a click event listener on it.
So you can copy the URL to the post. I hope I have understood it correctly?
document.addEventListener("click", function(e)
{
const textArea = document.createElement("textarea");
textArea.value = e.target.querySelector('.url-container').innerHTML;
document.body.appendChild(textArea);
textArea.select();
let successful = null;
let msg = '';
try {
successful = document.execCommand('copy');
msg = successful ? 'successful' : 'unsuccessful';
} catch (err) {
console.warning('unable to copy');
console.warning(err);
}
document.body.removeChild(textArea);
if (successful) {
alert('copied');
// make an XHR call to your App Api for counting
}
});
<button id="share" data-test="test"><textarea class="url-container" style="display:none;">www.your-domain.com/your-post-x</textarea>Share Post X</button>
Suppose I create a small component that takes an input and sets a label to show it.
app/components/testComponent/testComponent.xml:
<Label id="someLabel" loaded="onLoad"/>
app/components/testComponent/testComponent.js:
exports.onLoad = args => {
const obj = args.object;
const label = obj.getViewById('someLabel');
label.text = obj.someString || 'no string given';
};
Now I can use this component in any of my pages
<Page xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:testComponent="components/testComponent">
<StackLayout>
<testComponent:testComponent someString="hello {N}"/>
</StackLayout>
</Page>
This seems to be the official way to do it and it works. But is there a way to inject this component in the page using javascript only?
Yes, the Declarative UI (i.e. xml) is actually a building system that parses the xml and generates the JS so you don't have to.
So if you wanted to manually do this you would leave your component code alone and you would change your main screen code to be like this:
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="onLoad">
<StackLayout id='sl'>
</StackLayout>
</Page>
The first thing you will notice is we gave the Page a loaded event, you have to have somewhere to actually run your code to attach your component to the visual tree. The second thing we did was add to StackLayout an id; this technically isn't actually needed -- you can navigate the NS tree and find the proper StackLayout; but for simplicity adding a ID makes it a lot easier.
So the JS code in your page would be:
var builder = require('ui/builder');
var fs = require('file-system');
exports.onLoad = function(args) {
// Get our current Page that is being loaded
var page = args.object;
// Find our StackLayout
var stackLayout = page.getViewById('sl');
// Load our JS for the component
var path = fs.knownFolders.currentApp().path;
var componentJS = require(path + '/components/testComponent/testComponent.js');
// Actually have the builder build the Component using the XML & JS.
var component = builder.load(path + '/components/testComponent/testComponent.xml', componentJS);
// And add our component to the visual tree
stackLayout.addChild(component);
};
I believe that because you are adding the child in the loaded event that your page loaded event in the child component will be ran, but don't hold me to that one. If it isn't then you can manually run it a the same time you are adding it...
where filepath is a script - or even a class the callback function can create an instance of.
This is as if its loaded at page load and shows in most developer tool consoles.
var uuid='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
var url = filepath + "?" + uuid;//prevent caching - does not work with ajax setup
try {
$.getScript(url, "callbackfunctionname('" + filepath + "')");//getScript callback seems broken so use own
}
catch (e) {
//error handle
}
I have seen several posts coming close to solving my issue, but I am still not able to accomplish my simple task, which is this:
Imagine I have a window which contains a link to a remote file (most often it will be a zip file). How can I structure and call a function that accesses the file and opens a "Save As" dialogue so that the user can choose where to save the downloaded file? It would be nice to be able to pass different variables from other links to the same function to accomplish the same thing for other downloadable files.
And yes, I am completely new to TideSDK and not exactly a javascript expert, if this is causing much painful slapping of foreheads.
Try this.
Any link with a class of "save-as" will trigger the "Save as" dialog. The file will be saved AFTER the user selects the location, gives it a name and clicks Save. This does use jquery.
Download WordPress
<script>
$(function(){
var currentLink;
$('.save-as').click(function() {
var link = $(this).attr('href');
var filename = link.substring(link.lastIndexOf('/')+1);
currentLink = link;
Ti.UI.currentWindow.openSaveAsDialog(saveComplete, {
title: 'Save As...',
multiple: false,
defaultName : filename
});
return false;
}); // End save as.
var saveComplete = function(results) {
if(results.length>0) {
var downloadFile = results[0];
console.log("Download the file");
var httpClient = Ti.Network.createHTTPClient();
httpClient.open('GET', currentLink);
httpClient.receive(function(data) {
var file = Ti.Filesystem.getFile(downloadFile);
var fileStream = file.open(Ti.Filesystem.MODE_APPEND);
fileStream.write(data);
fileStream.close();
});
}
};
});
</script>
I have a flash file, (banner ad) and i need to have an image gallery and an flv player, which i have. to save space i've used a loader to call them via their swf file using a button. but when i do this it calls the swf on top of my main flash page constantly layering more and more pages on top of each other.
heres is my loader code:
var loadedSWF:Loader = null;
var req:URLRequest = new URLRequest("imagegallery.swf");
loadedSWF = new Loader();
loadedSWF.load(req);
function loadSWF(file:String, container:MovieClip=null):void
{
if(container == null) container = MovieClip(root);
// removes the previously loaded SWF
if(loadedSWF != null)
{
if(loadedSWF.parent) loadedSWF.parent.removeChild(loadedSWF);
}
addChild(loadedSWF);
}
imageGallery_btn.addEventListener(MouseEvent.CLICK, _click);
function _click(e:MouseEvent):void
{
loadSWF("imagegallery.swf");
}
It's some code i found on this website.