Display local html page in UWP WebView - javascript

I would like to display my local html page in a WebView. If I put my html page in the Application's local folder then I can point to it using the following code and it works:
webView.Navigate(new Uri("ms-appdata:///local/myHtmlPage.html"));
But I want to know if there is an equivalent Uri that takes my to the publisher cache folder? The reason I ask is I want to share the html page and it's data (files) between the applications I deploy. I have tried putting the html page in the publisher cache folder, then pointing the WebView's Navigate method to the html page's path but I can't get the WebView to open the page. I get some HRESULT exception with no details as to why it failed.
I want to open files in the html page without prompting the user to pick one and the only way I know how to do this is if the files are in a sub directory of the page's directory. I'll have a javascript function that opens the file using the path and I'll call this function from my UWP application and pass it the name of the file.
Help in this regard would be greatly appreciated.

Display local html page in UWP WebView
Sure, you could use StreamUriWinRTResolver to converter html file where in publisher folder to stream. And use WebView NavigateToLocalStreamUri to load that stream.
For example
public sealed class StreamUriWinRTResolver : IUriToStreamResolver
{
/// <summary>
/// The entry point for resolving a Uri to a stream.
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public IAsyncOperation<IInputStream> UriToStreamAsync(Uri uri)
{
if (uri == null)
{
throw new Exception();
}
string path = uri.AbsolutePath;
// Because of the signature of this method, it can't use await, so we
// call into a separate helper method that can use the C# await pattern.
return getContent(path).AsAsyncOperation();
}
/// <summary>
/// Helper that maps the path to package content and resolves the Uri
/// Uses the C# await pattern to coordinate async operations
/// </summary>
private async Task<IInputStream> getContent(string path)
{
// We use a package folder as the source, but the same principle should apply
// when supplying content from other locations
try
{
var filename = path.Remove(0, 1);
StorageFile f = await ApplicationData.Current.GetPublisherCacheFolder("Folder1").GetFileAsync(filename);
IRandomAccessStream stream = await f.OpenAsync(FileAccessMode.Read);
return stream.GetInputStreamAt(0);
}
catch (Exception e)
{
throw new Exception("Invalid path");
}
}
}
Usage
Uri url = MyWebView.BuildLocalStreamUri("MyTag", "ContentPage.html");
StreamUriWinRTResolver myResolver = new StreamUriWinRTResolver();
MyWebView.NavigateToLocalStreamUri(url, myResolver);

Related

How to open a preview file (pdf, docx, txt, etc.) in another page of the browser using Angular and Java

I am developing a web application using Angular 7 and Java 8. I am uploading a file (pdf, docx, txt etc...), but the problem is that I can't open it in another page of the browser through a RESTful web service. I am getting the error 415 Unsupported Media Type. I have tried with the POST and GET method whitout any success. These are the snippets of the code, front-end and back-end:
Angular component (method called by a button passing the path + filename example : C/doc/foo.pdf)
download(doc) {
this.service.downloadFile(doc.path).subscribe(response => {
if(response) {
let blob = new Blob([response], { type: 'text/json; charset=utf-8' });
const url= window.URL.createObjectURL(blob);
window.open(url);
}
});
}
Angular service
downloadFile(path): Observable<Blob> {
const url = '/download';
return this.http.post<Blob>(url, path, { responseType: 'blob' as 'json' });
}
Java Controller
#PostMapping(value = "download", produces = { MediaType.APPLICATION_JSON_UTF8_VALUE })
#ResponseBody
public byte[] download(#RequestBody String path) {
try {
return this.provvedimentoService.getDownload(path);
} catch (IOException | EgesException e) {
e.printStackTrace();
return null;
}
}
Java Service
public byte[] getDownload(String pathFile) throws EgesException, IOException {
Path path = Paths.get(pathFile);
if(path.toFile().exists())
return Files.readAllBytes(path);
else
throw new EgesException(EgesExceptionConstants.WARNING_ACT_NOTFOUND_EXCEPTION);
}
You can't. Browsers don't have any built-in way to view Word docs so unless the user has configured their browser to open it with some plugin (which 99% of the world hasn't done), the browser will prompt them to download the file.
No browsers currently have the code necessary to render Word Documents, and as far as I know, there are no client-side libraries that currently exist for rendering them either.
However, if you only need to display the Word Document, but don't need to edit it, you can use Google Documents' Viewer via an <iframe> to display a remotely hosted .pdf/ .doc/.docx /.txt etc
<iframe src="https://docs.google.com/gview?url=http://remote.url.tld/path/to/document.doc&embedded=true"></iframe>
Many people used this methods to view their documents file. you can check here:How to display a word document using fancybox
<iframe width="100%" height="300px" src="https://docs.google.com/gview?url=http://index-of.co.uk/Google/googlehacking.pdf&embedded=true"></iframe>
You can add your document file URL like this
https://docs.google.com/viewer?url=<url for your file>&embedded=true
Here will be your file url <url for your file>
You have another way to view the .pdf/ .doc/.docx /.txt etc like google iframe system of Microsoft Document viwer webapp.
You can use it like this.
<iframe src='https://view.officeapps.live.com/op/embed.aspx?src=http://writing.engr.psu.edu/workbooks/formal_report_template.doc' width='80%' height='800px' frameborder='0'></iframe>
<iframe src='https://view.officeapps.live.com/op/embed.aspx?src=http://writing.engr.psu.edu/workbooks/formal_report_template.doc' width='80%' height='800px' frameborder='0'></iframe>
A solution adapted from "How do I render a Word document (.doc, .docx) in the browser using JavaScript?".
This is an embedded Microsoft Office document, powered by Office Online.
embed.aspx?src=<your_will_be_your_document_file_url>' width='80%'
add your document file ur here <your_will_be_your_document_file_url>

How to access elements under `shadow-root` at 'chrome://downloads' using jquery and selenium?

I am trying to get the name of the last downloaded file in my selenium javascript application.
I have my selenium driver navigating to the chrome downloads page using: driver.get('chrome://downloads'); , but when I get there, selenium is not able to find ANY elements on the download page.
The chrome downloads page 'chrome://downloads' has a bunch of shadow-root elements that I don't know how to get underneath in order to access the id's that I want. How do I access identifiers beneath shadow-root items?
I want to get $("#file-link") as shown here:
But when I use jquery to find it, everything returns null (probably because it's behind shadow-root)
Here's a big picture of all the information I have including showing that "#file-link" totally exists:
The code I am using to wait for the element to exist is the same that I use for all elements in my application, so I think this is already working:
driver.wait(until.elementLocated(By.id('downloads-manager')), 120000).then(function(){
console.log("#downloads-manager shows");
driver.findElement(By.id('downloads-manager')).then(function(dwMan){
//How do I "open" #shadow-root now? :(
});
});
Here is my version information:
Chromium v54.0.2840.71
Node v6.5.0
ChromeDriver v2.27.440175
selenium-webdriver v3.4.0
Similar Question
Selenium webdriver can't find elements at chrome://downloads (This is the same problem I am having but in python)
Links
Selenium Javascript API: https://seleniumhq.github.io/selenium/docs/api/javascript/
The $ from your example is not a shorthand for JQuery.
It's function overridden by the page to locate an element by id only:
function $(id){var el=document.getElementById(id);return el?assertInstanceof(el,HTMLElement):null}
To select through the shadow DOM, you need to use the '/deep/' combinator.
So to get all the links in the download page:
document.querySelectorAll("downloads-manager /deep/ downloads-item /deep/ [id=file-link]")
And with Selenium:
By.css("downloads-manager /deep/ downloads-item /deep/ [id=file-link]")
Why not check the downloads folder directly? I do this for downloading Excel files. I first clear the downloads folder, click the button to download the file, wait ~5 sec (varies by file size, internet speed, etc.), and then looking in the folder for a "*.xlsx" file. This also has the benefit of working with any browser.
C# Examples:
/// <summary>
/// Deletes the contents of the current user's "Downloads" folder
/// </summary>
public static void DeleteDownloads()
{
// Get the default downloads folder for the current user
string downloadFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\Downloads";
// Delete all existing files
DirectoryInfo di = new DirectoryInfo(directoryPath);
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in di.GetDirectories())
{
dir.Delete(true);
}
}
/// <summary>
/// Looks for a file with the given extension (Example: "*.xlsx") in the current user's "Download" folder.
/// </summary>
/// <returns>Empty string if files are found</returns>
public static string LocateDownloadedFile(string fileExtension)
{
// Get the default downloads folder for the current user
string downloadFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\Downloads";
DirectoryInfo di = new DirectoryInfo(downloadFolderPath);
FileInfo[] filesFound = di.GetFiles(fileExtension);
if (filesFound.Length == 0)
{
return "No files present";
}
else
{
return "";
}
}
And then in my Test I can Assert.IsEmpty(LocateDownloadedFile); This way if the assert fails, the error message if printed.
Expected: String.Empty.
Actual: No files present.

Webview loadUrl() from file on local storage (not assets)

I'm working on a code piece which must load html file to my custom webview. I'm moving my file out of assets to a local folder. And from there I need to read the html to a webview. I need to move the file from assets folder so please don't suggest anything about assets.
This is how I move files:
File f = new File(context.getFilesDir()+"/TMP/");
try {
String[] assets = {"editor.html", "normalize.css", "rich_editor.js", "style.css"};
for(String a : assets)
{
InputStream is = context.getAssets().open(a);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
FileOutputStream fos = new FileOutputStream(f + a);
fos.write(buffer);
fos.close();
}
} catch (FileNotFoundException e) { }
catch (IOException ex)
{
ex.printStackTrace();
}
This is how I'm trying to read it.
loadUrl("file://"+ new File(context.getFilesDir()+"/TMP/editor.html").getAbsolutePath());
I don't get an error or anything. But I do get a white screen and nothing else. I have thought that it might not be loading Javascript or CSS. But loading JS is enabled so it must work. Is any aditional editing required for html file due to moving it from one folder to another?
Update:
I know that the file is coppied successfully because I have checked it from inside the code and it's all good. I believe the problem is in the WebView method or linking.
I have also tried loadData and loadDataWithBaseURL(). Both work the same. Blank screen

Download WebView content in WInRT application

I'm trying to build a universal rss application for Windows 10 that could be able to download the content of the full article's page for offline consultation.
So after spending a lot of time on stackoverflow I've found some code:
HttpClientHandler handler = new HttpClientHandler { UseDefaultCredentials = true, AllowAutoRedirect = true };
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(ni.Url);
response.EnsureSuccessStatusCode();
string html = await response.Content.ReadAsStringAsync();
However this solution doesn't work on some web page where the content is dynamically called.
So the alternative that remains seems to be that one: load the web page into the Webview control of WinRT and somehow copy and paste the rendered text.
BUT, the Webview doesn't implement any copy/paste method or similar so there is no way to do it easily.
And finally I found this post on stackoverflow (Copying the content from a WebView under WinRT) that seems to be dealing with the same exact problematic as mine with the following solution;
Use the InvokeScript method from the webview to copy and paste the content through a javascript function.
It says: "First, this javascript function must exist in the HTML loaded in the webview."
function select_body() {
var range = document.body.createTextRange();
range.select();
}
and then "use the following code:"
// call the select_body function to select the body of our document
MyWebView.InvokeScript("select_body", null);
// capture a DataPackage object
DataPackage p = await MyWebView.CaptureSelectedContentToDataPackageAsync();
// extract the RTF content from the DataPackage
string RTF = await p.GetView().GetRtfAsync();
// SetText of the RichEditBox to our RTF string
MyRichEditBox.Document.SetText(Windows.UI.Text.TextSetOptions.FormatRtf, RTF);
But what it doesn't say is how to inject the javascript function if it doesn't exist in the page I'm loading ?
If you have a WebView like this:
<WebView Source="http://kiewic.com" LoadCompleted="WebView_LoadCompleted"></WebView>
Use InvokeScriptAsync in combination with eval() to get the document content:
private async void WebView_LoadCompleted(object sender, NavigationEventArgs e)
{
WebView webView = sender as WebView;
string html = await webView.InvokeScriptAsync(
"eval",
new string[] { "document.documentElement.outerHTML;" });
// TODO: Do something with the html ...
System.Diagnostics.Debug.WriteLine(html);
}

Load file after page is complete without redirecting

I am trying to do pretty much the same, as is for example on Sourceforge. After a user creates some data, I generate a file and I want it to be offered to him after a page load. However, I know almost nothing about javascript and simple copy-paste of
<script type="text/javascript">
var download_url = "http://downloads.sourceforge.net/sourceforge/itextsharp/itextsharp-4.1.2-dll.zip?use_mirror=dfn";
function downloadURL() {
if (download_url.length != 0 && !jQuery.browser.msie) {
window.location.href = download_url;
}
}
jQuery(window).load(downloadURL);
</script>
is not enough. It is important for the user to download the file, so how to do that?
A question related to the previous is - where to store the file i created? Once while using the asp.net development server and then on the real IIS server? And how should this address look? When I tried
setTimeout("window.location.href='file://localhost/C:/Downloads/file.pdf'", 2000);
I was getting nothing, with HTTP an error of unknown address.
See Haack's DownloadResult example. It explains (I think) exactly what you're truing to do. Except you would provide the timeout call with your download action url.
you're asking the user's browser to look for a file on their own computer... that you're trying to save there.
you could use something like:
window.location.href='http://www.yourServer.com/generatePDF.asp?whatever=whatever'
where http://www.yourServer.com/generatePDF.asp?whatever=whatever is what is generating the pdf file for the user
On the server, you have to set the content disposition in the response header to "Attachment" as described in these answers.
If you do that, the download will not affect the page that is currently displayed in the browser. So, if you initiate a request in Javascript that gets an attachment, the browser will leave the page alone, and the user will see a message box with the Open/Save/Cancel question.
You can create your own PdfResult which extends ActionResult like this:
public class PdfResult : ActionResult
{
public byte[] Content { get; set; }
public string FileName { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.AddHeader("content-disposition", "attachment; filename=" + this.FileName);
response.AddHeader("content-length", this.Content.Length.ToString());
response.ContentType = "application/pdf";
using (MemoryStream memoryStream = new MemoryStream(this.Content))
{
memoryStream.WriteTo(response.OutputStream);
}
response.End();
}
Then in your action you can simply return the file as follows:
public ActionResult Pdf(string param1...)
{
var content = GeneratePdf(); //etc
var fileName = AssignFileName();
return new PdfResult { Content = content, FileName = fileName + ".pdf" };
}
A couple of different things. First, since you are using MVC, create an action that actually generates the file and returns it as a FileResult. The file can be an actual file on the server, but it can also be generated dynamically -- say in a MemoryStream -- and the FileResult created from that. Set the content to application/octet-stream or the actual file type if it's not one that will render in the browser via a plugin. Second, don't generate the file in the action that renders the page, but rather call the action that generates the FileResult from that page using the technique you've referenced (though it looks like they are doing something different for IE). If the MIME type is not one that can be rendered it will be downloaded.
public ActionResult GenerateFile( string value, int other )
{
MemoryStream file = new MemoryStream();
...
return File( file, "application/octet-stream" );
}

Categories

Resources