How do you serve a file without leaving the page? - ajax

Aims
I'm trying to let users download a file (myfile.zip in this case) by clicking a button on the page, without them leaving the page - ie the browser must stay on the current page, and leave them in a position where they can continue to use the page, including clicking the button again (should they wish to get a new copy of the file).
I need this to work across all browsers (IE6-8, Firefox, Chrome, Opera, Safari).
Background
Packaged inside the zip is a selection of stuff based on their other interactions (some of which may be partially complete) from the same page (this is all done via ajax) and I don't want them to leave the page as they would lose any unsaved changes.

Add the following header when the download file is served:
Content-disposition: attachment; filename=filename.zip
Most browsers will wait to see what type of thing they are loading before they clear the current page, and if it something that should be downloaded as a file they won't navigate away from the current page (they'll show a Save As dialog in front of the page, which can be dismissed to return to the page).
If however you find that a certain browser does navigate away from the current page, you may try having the link to the download contained in a small iframe, so only that frame changes.
I think it's a better solution to opening the link in a new window, because some browsers will leave the new window up even once it's determined that it is a file that should be downloaded, so you end up with a blank window.

If you make the link open in a new window/tab (e.g. via the <a> tag's target="_blank" attribute), it won't disturb the contents of the current window.
The target attribute is deprecated, but widely supported. Depending on the browser, you may also be able to use the CSS3 target-name property.
If your goal is to absolutely guarantee that the main window is undisturbed, this is likely the safest method, as it's resilient against download errors.

To avoid leaving the page (if you do this the page tries to close itself first, so that it's sure that you've saved everything, and you get warning messages if you haven't) or leaving blank tabs (which I don't like, nor the use of the depreciated target attribute) I've used an iframe, whose src attribute is changed in javascript.
This works everywhere except some versions of Opera, which I have considered an acceptable loss (I might fix that via the use of one of the other solutions plus browser detection later).

I believe if you direct the user to a file and the MIME type is something the browser knows it must download vs render, the browser will not leave the page. For instance if you were serving a zip file the browser would know it was a zip file and prompt for download. But if you were going to serve a zip file from a page request (i.e. /file.aspx?file=myinfo.zip) then file.aspx would need to change the MIME type to be "application/zip" before send back the response in order to prompt the user for the download.
One major caveat here is if the file didn't exist for some reason the user would get a 404 and be directed to the error page.
As a sure-fire way of not redirecting the user you could open a pop-up for downloading.

We do this on postback on an aspx page by setting ContentType to "application/octet-stream", then streaming the zipfile with Response.BinaryWrite(..) and Response.Flush().
Gives the user a popup "do you want to open or save" the file.
Page is still available.

By the way, specifying the appropriate content disposition header alone might not work in all browsers. Specifically, I've seen it not work in Opera, and IE7 displays the yellow security warning bar.
In addition to the appropriate header, as described by thomasrutter, The way I've done this is by using a hidden form:
<form id="download_form" method="get" action=""></form>
When the user clicks a button, you can manipulate the "action" attribute of the form with the URL of the file.
This seems to work in all browsers, even IE7!

Related

Content Script Injection at Install for Firefox Web Extension

If content scripts are specified in manifest.json for Firefox, Firefox will also load content scripts for already opened tabs and execute them even the tabs are already in loaded and ready state.
Google Chrome does not add any content script when extension is installed for already opened tabs. The content script is loaded when the page is refreshed for the older tabs.
I want to ask is Firefox's behavior is expected or bug?
As far as compatibility goes, it's a bug.
Chrome does not do that.
As a result, many extensions implement custom logic to achieve the effect.
One has to take into account side effects. Suppose your content script injects some UI into the page. Then the extension is updated. That amounts to extension restart, and suddenly you have 2 copies of the UI. Also valid if you just attach event listeners, as (at least in case of Chrome) the old content script's context continues to exist (in an "orphaned" state).
The last point is very important and probably the reason why Chrome doesn't do it by default. At some point I made a very long post about this problem - if you're going to report this as a bug to Mozilla, please include that. There's also this feature request that is related.
What would be sensible (and backwards compatible) is to add a parameter to content script description in the manifest - whether to inject into existing pages. It will be up to developers to guarantee that side effects are taken care of. This usually requires even more code to just communicate to the old script that it needs to wind down and clean up.

Lock Firebug to a specified page

Is there a way to keep Firebug on a single page, so that when I switch pages it remains on the page I want it set to?
For example, I'm working on a project and I get an error that I want to search for on Stack Overflow, but when I navigate here, the console changes to reflect this site. I'd like to stop that from happening.
There is no option to "pin" a page's data in Firebug (as of version 2.x). As far as I know this also doesn't work in any of the browser built-in dev tools.
Though the simple solution for your problem is to open the other page in a separate tab or window. Doing so keeps all the data of the page saved when you switch back to the tab containing your project's page.
Note that Firebug's activation model is based on URLs following the same origin policy. I.e. if you open it for your project's page, it will always get opened for your projects page, even on other tabs, but not for any other site.
I've found it useful to split the tab of interest off into a new window and to activate Firebug on that window. That way I can continue using my original tab collection/window without it changing as I link-hop.

View or Open in Browser vs. Download

I am using HTML and CSS, and willing to use a very simple JavaScript code if necessary.
I uploaded ResumeWord.doc and ResumePDF.pdf to the FTP. I created links for "View" "Download" and "Print" for each. ResumeWord.doc only seems to give me a pop-up with options to Open or Save instead of opening in the browser, while I was able to open ResumePDF.pdf in the browser but not create a clickable link to download it without viewing. I have tried the HTML target_blank and JavaScript window.open for the "View", unsuccessfully. I am self-taught and an amatuer.
How can I make the "View" link open ResumeWord.pdf in the browser without a pop-up?
How can I get ResumePDF.pdf to download when the user clicks "Download"?
Without some help, the browser won't assume that a user has Microsoft Word installed on their computer. That is why you only get the option to save it, rather than it opening.
The PDF, however, is something that can be viewed in-browser, and the browser can check if the right files are installed to make this happen. So if they are, the browser goes ahead and opens the file.
As for forcing the browser to open a word file, see this SO question.
And as for forcing a download of a PDF, see this SO question. It may not be possible, in your case, as the solution involves sending different server-side headers.

Firefox Extension that copies HTML link to current web page to clipboard and not just the URL

The Situation
I need to automate the copying of a HTML link to the current page that
is viewed in the current Firefox Tab into other WYSIWYG editors. This
is not the same as copying just the plain-text of the URL, nor is it
the same as pasting just the plain-text of the web pages title. This
is also not the same thing as navigating to some other web page that
has the HTML link to the page of interest, selecting the text with the
mouse cursor, and typing CTRL-C to copy it into the current operating
systems clipboard (both Linux and Windows, should not make any
difference). Only the update to the clipboard is to be automated; the
pasting from the clipboard into the target application will be done
manually.
The desired use case is as follows:
The user browses to any web page from within Firefox.
The user types some user-specified key sequence that is not
in conflict with standard Firefox built-in key bindings.
Firefox will then do only part of what Copy Link Bookmarklet
does: Instead of opening up a new separate window/tab and
constructing and rendering the HTML for the link, and then
requiring the user to waste motion in selecting and copying the
link into the clipboard, the extension will then format the HTML
itself and copy that into the clipboard directly.
The user then selects any of the targets described below and
types CTRL-V to paste the formatted text.
The user then sees the link as a link in that target area, and does
not see anything literal like http://...
For example, if the webpage browsed to was http://www.google.com, and
the user clicked the user-defined key sequence, and if the user pasted
it into some Google Document, what they would see in that document is
not http://www.google.com nor would they see Google, but instead
would see what you would see when you read this in StackOverflow in a
web browser: Google
Now, there are Firefox extensions and bookmarklets that come close,
but they all involve no net reduction in mouse motion and/or key press
overhead, which is the most time-wasting aspect of this frequently
occuring use case. My searches for an existing extension turned
up nothing that exactly meets my needs (see Research section
below). Therefore, I think I may need to roll my own extension (or
modify an existing one), unless someone can point me to an existing
extension that provides this functionality.
The extension I have in mind should work in Firefox version 11 or
greater running on either Linux or any version of Windows. Only
Firefox and a suitable Firefox extension should be needed, and not any
other special software.
Targets of the paste should be:
GMail compose text areas
Google Documents
Microsoft Word documents
Microsoft Outlook compose text areas.
Any other WYSIWYG editor such as the Blogger post editor.
Notepad (in which case it is the web page title that is pasted only
and not the URL, or both the web page title and URL as separate
plaintext; either way).
About user-specified key bindings: If there was an extension already
that did the above but without providing the ability to bind a
keybinding to it, then I would expect to be able to use the keyconfig
extension extension to handle that aspect. Actually, that might
even be preferable; I don't know yet.
Research
Below are approaches I investigated that came close to what I want,
but did not exactly meet the need:
Hacking on Copy Link Bookmarklet won't work because, from what I can tell, there is no way to update the OS's clipboard from a bookmarklet, hence why I think that a Firefox extension is required.
In a Firefox extension, how can I copy rich text / links to the clipboard?
3 FireFox Addons to Easier Copy Links and Anchor Texts -- None of the extensions listed do what I want because they force you to use the right mouse button and navigate down one or two levels of context menu, which is wasted motion.
Copy Link Text (CoLT) -- CoLT also supports copying a hyperlink and it’s associated text as a rich-text formatted link, however it does not include a default keybinding. It looks like someone else is attempting to tie keyconfig to CoLT, which might be an option as a solution.
Copy URL Plus -- Looks like it has the copy-to-clipboard logic, but doesn't look like it has been maintained since Firefox 1.x timeframe.
I am answering my own question:
The CTRL-SHIFT-F11 binding will silently stop working if both keysnail and keyconfig are installed into the same Firefox browser. The fix for me was to simply uninstall keysnail as I don't use it.
I did not actually need to write my own Firefox extension, but I did
need to scrape out a bit of code that copies the richtext link from
the Copy Link Text (CoLT) extension and apply it directly as a
binding into the keyconfig extension as follows:
Install the keyconfig extension.
Restart Firefox.
After Firefox loads up, type CTRL-SHIFT-F12 to bring up the keyconfig configuration menu.
On the bottom of the page, click on the Add a new key button.
In the Name field, type in some suitable name such as Copy Rich Text Link to Current Page.
Type in the following chunk of Javascript code (This code I carved
out of the objCoLT.CopyBoth function inside the content/colt.js
file inside the Copy Link Text (CoLT) extension):
var url = content.document.location.href;
var text = content.document.title;
// Use the users selection instead of the title if text is selected:
var selection = document.commandDispatcher.focusedWindow.getSelection().toString();
if (selection != "")
{
text = selection;
}
var richText = "" + text + "";
var xfer = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
xfer.addDataFlavor("text/html");
var htmlString = Components.classes["#mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
htmlString.data = richText;
xfer.setTransferData("text/html", htmlString, richText.length * 2);
var clipboard = Components.classes["#mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
clipboard.setData(xfer, null, Components.interfaces.nsIClipboard.kGlobalClipboard);
Click Ok.
Back in the main Keyconfig dialog, <disabled> should be shown in the text field to the left of the Apply button.
Click in that text field, and type the keybinding you want to associate with it, such as CTRL-SHIFT-F11.
Click the Apply button.
Click the Close button to close the Keyconfig configuration dialog box.
To test this out, proceed as follows:
In Firefox, navigate to some arbitrary page.
Type in CTRL-SHIFT-F11 (or whatever keybinding you chose above).
Notice that no dialog boxes popup; that is intentional.
Open up Google Documents, and Create a new document.
Click in the new document, and type CTRL-V.
You should see the HTML/rich-text form of the link pasted in.
Click on the link and then click on the URL to the left of Change.
The browser should open up the original page corresponding to that URL.
I have been able to copy URL as HTML with the following bookmark:
javascript: navigator.clipboard.write([new ClipboardItem({ ["text/html"]: new Blob([`${document.title}`], { type: "text/html" }) })]);
Unfortunately in firefox the Clipboard write API still requires to set thedom.events.asyncClipboard.clipboardItem to true in about:config.
Several extensions exist that offer copying of title and URL but few seem to support Rich Text creation. The key is that the copied text needs to be formatted in html with a href and it needs to be copied as a text/html type.
The extension I went with in the end is CopyTabTitleUrl. (GitHub) It supports both requirements and also has a keybind feature along with a toolbar button that can also function as a single-click copy.
Set the Format option to:
${title}
Then Activate Extended Mode and make sure to check the "Copy in text/html format" option in Other. After that, using the format copy, the result can be correctly pasted into Office applications. And Stack Exchange evidently as the links above were created by the add-on.
Note that the Edge implementation of URL copying seems to be somewhat different still. With a default plaintext paste, Edge will just paste in the URL while this approach will of course paste unformatted HTML. But it's close enough.

Differences in Internet Explorer and Firefox when dynamically loading content then going forward and back

I'm developing a web application where, due to slow database access, not all content in a page is loaded immediately but rather dynamically when the user clicks a button after optionally making a selection.
This works fine. However, after dynamically loading content, if I navigate to a different web page, then navigate back, in Internet Explorer the loaded content will have disappeared, i.e. the page will have reverted to the originally retrieved page. In Firefox (and Opera as well), however, the loaded content will still be there, i.e. the page will look like it did before I navigated away from it.
The Firefox behaviour is the desired behaviour in my case, as the user would routinely navigate to subpages and go back to the main page. My question is therefore, is there any way I can force Internet Explorer to exhibit this behaviour, or are there any possible workarounds to get the desired result?
Here is my workaround solution for IE. It utilizes the fact that, even if the DOM is reset when navigating away and back to a page, input field values are still remembered.
For every dynamically loaded element, I also have a hidden input field where I "cache" the loaded value. I then have a function transferFromCache() which copies the values from each hidden input field to the corresponding element. This function is run at page init - which, in IE's case, is at page load AND every time one navigates back to the page.
This technique could probably be used to store the values of javascript variables as well.
I don't think there's a method to get IE to emulate FF in this manner. The reason is to do with fairly fundamental aspects of the browsers. FF uses a mechanism for it's page history called 'Fast DOM caching' which (from my limited understanding) basically means that when it puts a page into the browser history then it will store the current DOM (so the current page state) in a serialised format, which means that when the page is reloaded from history the state is preserved and FF can do this much quicker as a lot of work is already done (parsing the HTML into a DOM, etc). In comparison, IE will simply store the HTML received initially as it's history file and will reload it when navigating history.
Here is an article about saving state in session variables, which may help

Resources