问题描述
在许多网站上(例如 Dropbox 是一个很好的示例),当您单击文档进行下载时,它会打开一个新的窗口/标签,然后出现下载提示,并且该标签/窗口立即关闭自身(而提示保持打开状态).
如何使用javascript复制此行为?
我认为一种方法是检测该下载提示的出现,然后使用window.close()
.但是,我不确定如何检测到该特定提示.
首选跨浏览器解决方案,但是任何在Firefox中可以使用的解决方案都是值得赞赏的.
说明
- 我正在用Greasemonkey脚本执行此操作
- 在新标签中打开的链接"不一定是指向文档的直接链接.有时它是一个简单的页面,在后台开始下载.我指的是具有特殊下载"页面的网站的类型……说您的下载将很快开始,如果没有开始,请单击此处"的网站.
更多说明:关于上面说明2中提到的网站类型,我要做的是单击下载链接,在新窗口中加载特定的下载页面,然后启动下载后,关闭窗口.
您需要三个基本部分:
- 您必须拦截下载链接.
- 单击链接时,您必须将链接发送到新选项卡,而不仅仅是使用
target="_blank"
对其进行修改.该选项卡必须使用javascript打开,以便在时间到时允许javascript将其关闭. - 您的脚本还必须运行/处理弹出窗口"标签,以便它可以检测何时关闭弹出窗口.
对于此讨论,请参考 jsFiddle上的此测试页.它的结构如下:
<div id="downloadLinks">
<ul>
<li><a class="dwnPageLink" href="http://fiddle.jshell.net/cDTKj/show/">
Test file, download page at jsFiddle
</a>
</li>
<li><a class="dwnPageLink" href="http://dw.com.com/redir...">
TextPad (a great text editor), download page at CNET / Download
</a>
</li>
</ul>
</div>
每个a.dwnPageLink
链接都打开一个下载页面",该页面会在短暂的延迟后自动开始文件下载.
拦截下载链接(a.dwnPageLink
):
我们这样拦截链接:
$("#downloadLinks a.dwnPageLink").each (interceptLink);
function interceptLink (index, node) {
var jNode = $(node);
jNode.click (openInNewTab);
jNode.addClass ("intercepted");
}
请注意,我们还添加了CSS类,以便我们可以快速查看哪些链接受到了影响.openInNewTab
将在下面详细说明.它必须同时打开一个标签页,并且必须停止正常的链接操作.
将链接发送到新标签页:
我们必须使用window.open()
来处理链接.如果未通过window.open
打开页面,则脚本将无法将其关闭.
请注意,不能使用 GM_openInTab()
,因为它不会导致正确设置window.opener
否则不提供关闭打开的标签页的机制.
新标签页在openInNewTab
中启动,如下所示:
function openInNewTab (zEvent) {
//-- Optionally adjust the href here, if needed.
var targURL = this.href;
var newTab = window.open (targURL, "_blank");
//--- Stop the link from doing anything else.
zEvent.preventDefault ();
zEvent.stopPropagation ();
return false;
}
处理弹出"标签:
无法从启动页面监视文件"对话框.因此,我们必须将脚本设置为也可以在弹出"标签上运行.相应地添加@include
指令.
脚本的弹出部分可以通过监视beforeunload
事件来检测文件"对话框.在打开文件"对话框之前(以及在选项卡关闭之前,浏览器将触发beforeunload
事件).
但是,当对话框出现时,我们不能仅关闭选项卡.这样做也会关闭对话框.因此,我们增加了一个小的时间延迟,并添加了一个确认"对话框,以便该选项卡将保持打开状态,直到关闭文件"对话框.要清除确认"对话框,只需再按一次(或单击 OK ).
代码如下:
$(window).bind ("beforeunload", function (zEvent) {
//-- Allow time for the file dialog to actually open.
setTimeout ( function () {
/*-- Since the time it takes for the user to respond
to the File dialog can vary radically, use a confirm
to keep the File dialog open long enough for the user
to act.
*/
var doClose = confirm ("Close this window?");
if (doClose) {
window.close ();
}
},
444 // 0.444 seconds
);
} );
注意:
- 由于脚本将同时在列表"页面和下载"页面上运行,因此可以通过选中
window.opener
来确定哪个脚本.在使用javascript打开的页面上,该页面的值将为非null. - 此问题并未询问有关在后台加载标签页的问题.可以做到这一点,并取得不同程度的成功,但这是一个更复杂的过程.提出一个新问题.
完整脚本:
// ==UserScript==
// @name _Download page, auto closer
// @namespace _pc
// ******** Includes for "List pages" that have the links we might click...
// @include http://YOUR_SERVER.COM/YOUR_LIST-PAGE_PATH/*
// @include http://jsbin.com/ozofom/*
// @include http://fiddle.jshell.net/qy3NP/*
// @include http://download.cnet.com/*
// ******** Includes for "Popup pages" that do the actual downloads...
// @include http://YOUR_SERVER.COM/YOUR_POPUP-PAGE_PATH/*
// @include http://fiddle.jshell.net/cDTKj/*
// @include http://dw.com.com/redir?*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @grant GM_addStyle
// @grant GM_openInTab
// ==/UserScript==
/*- Important: The @include or @match directives must for for both the pages
that list the download links, AND the pages that do the actual downloading.
The @grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
var bPageNotOpenedByJavascript = window.opener ? false : true;
if (bPageNotOpenedByJavascript) {
/***** "Normal" page, which might contain links to special download pages.
*/
//--- Intercept links to the download pages:
// For our jsFiddle Test page:
$("#downloadLinks a.dwnPageLink").each (interceptLink);
// For CNET/Download:
$("#downloadLinks div.dlLinkWrapper a").each (interceptLink);
GM_addStyle ( " \
a.intercepted { \
background: lime; \
} \
" );
}
else {
/***** Page opened by JS in either a popup or new tab.
This was *most likely* done by us, using window.open.
*/
$(window).bind ("beforeunload", function (zEvent) {
//-- Allow time for the file dialog to actually open.
setTimeout ( function () {
/*-- Since the time it takes for the user to respond
to the File dialog can vary radically, use a confirm
to keep the File dialog open long enough for the user
to act.
*/
var doClose = confirm ("Close this window?");
if (doClose) {
window.close ();
}
},
444 // 0.444 seconds
);
} );
}
function interceptLink (index, node) {
var jNode = $(node);
jNode.click (openInNewTab);
jNode.addClass ("intercepted");
}
function openInNewTab (zEvent) {
//-- Optionally adjust the href here, if needed.
var targURL = this.href;
var newTab = window.open (targURL, "_blank");
//--- Stop the link from doing anything else.
zEvent.preventDefault ();
zEvent.stopPropagation ();
return false;
}
On many websites (Dropbox being a good example), when you click on a document to download it, it opens a new window/tab, then the download prompt appears, and the tab/window immediately closes itself (while the prompt remains open).
How do I replicate this behavior using javascript?
I think one approach would be to detect the appearance of that download prompt, then use window.close()
. However, I'm not sure how to detect that particular prompt.
A cross-browser solution is preferred, but anything that'll work in Firefox is greatly appreciated.
Clarifications
- I'm doing this in a Greasemonkey script
- The "link" that opens in the new tab is not necessarily a direct link to the document. Sometimes it is a simple page that starts the download in the background. I'm referring to the type of sites that have their special "download" page...the ones that say something like "your download will begin shortly, if it doesn't start, please click here".
More clarification: With regards to the type of website mentioned in clarification 2 above, what I want to do is click on the download link, have that particular download page load in a new window, and have the window close once the download has been initiated.
There are three basic parts to what you want:
- You must Intercept the download links.
- You must send the link to a new tab when it is clicked, and not just modify it with
target="_blank"
. The tab must be opened with javascript, so that javascript will be allowed to close it when the time comes. - Your script must also run-on / handle the "popup" tab, so that it can detect when to close the popup.
For this discussion, refer to this test page at jsFiddle. It is structured like this:
<div id="downloadLinks">
<ul>
<li><a class="dwnPageLink" href="http://fiddle.jshell.net/cDTKj/show/">
Test file, download page at jsFiddle
</a>
</li>
<li><a class="dwnPageLink" href="http://dw.com.com/redir...">
TextPad (a great text editor), download page at CNET / Download
</a>
</li>
</ul>
</div>
where the a.dwnPageLink
links each open a "Download page" -- which automatically starts a file download after a short delay.
Intercept the download links (a.dwnPageLink
):
We intercept the links like so:
$("#downloadLinks a.dwnPageLink").each (interceptLink);
function interceptLink (index, node) {
var jNode = $(node);
jNode.click (openInNewTab);
jNode.addClass ("intercepted");
}
Note that we also add a CSS class, so that we may quickly see which links have been affected.openInNewTab
will be detailed below. It must both open a tab, and it must stop the normal link action.
Send the link to a new tab:
We must use window.open()
to handle the link. If the page is not opened via window.open
, our script will not be able to close it.
Note that GM_openInTab()
cannot be used because it does not cause window.opener
to be set properly and otherwise does not provide a mechanism to close the opened tab.
The new tab is launched in openInNewTab
, which looks like this:
function openInNewTab (zEvent) {
//-- Optionally adjust the href here, if needed.
var targURL = this.href;
var newTab = window.open (targURL, "_blank");
//--- Stop the link from doing anything else.
zEvent.preventDefault ();
zEvent.stopPropagation ();
return false;
}
Handle the "popup" tab:
It is not possible to monitor for the File dialog from the launching page. So we must set the script to also run on the "popup" tab. Add @include
directives accordingly.
The popup portion of our script can detect the File dialog by monitoring the beforeunload
event. Browsers will fire the beforeunload
event, just before opening the File dialog (and also just before the tab closes, but we can ignore that).
However, we cannot just close the tab when the dialog appears. Doing so will close the dialog too. So we add a small time delay, and a "Confirm" dialog so that the tab will stay open until the File dialog is closed. To clear the Confirm dialog, just hit an extra time (or Click OK).
The code looks like this:
$(window).bind ("beforeunload", function (zEvent) {
//-- Allow time for the file dialog to actually open.
setTimeout ( function () {
/*-- Since the time it takes for the user to respond
to the File dialog can vary radically, use a confirm
to keep the File dialog open long enough for the user
to act.
*/
var doClose = confirm ("Close this window?");
if (doClose) {
window.close ();
}
},
444 // 0.444 seconds
);
} );
Note:
- Since the script will be running on both "List" pages and "Download" pages, we can tell which is which by checking
window.opener
. On a page opened by javascript, this will have a non-null value. - This question did not ask about having the tab load in the background. That can be done, with varying degrees of success, but is a more involved. Ask a new question for that.
Complete script:
This script works on the test page and on CNET / Download pages:
// ==UserScript==
// @name _Download page, auto closer
// @namespace _pc
// ******** Includes for "List pages" that have the links we might click...
// @include http://YOUR_SERVER.COM/YOUR_LIST-PAGE_PATH/*
// @include http://jsbin.com/ozofom/*
// @include http://fiddle.jshell.net/qy3NP/*
// @include http://download.cnet.com/*
// ******** Includes for "Popup pages" that do the actual downloads...
// @include http://YOUR_SERVER.COM/YOUR_POPUP-PAGE_PATH/*
// @include http://fiddle.jshell.net/cDTKj/*
// @include http://dw.com.com/redir?*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @grant GM_addStyle
// @grant GM_openInTab
// ==/UserScript==
/*- Important: The @include or @match directives must for for both the pages
that list the download links, AND the pages that do the actual downloading.
The @grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
var bPageNotOpenedByJavascript = window.opener ? false : true;
if (bPageNotOpenedByJavascript) {
/***** "Normal" page, which might contain links to special download pages.
*/
//--- Intercept links to the download pages:
// For our jsFiddle Test page:
$("#downloadLinks a.dwnPageLink").each (interceptLink);
// For CNET/Download:
$("#downloadLinks div.dlLinkWrapper a").each (interceptLink);
GM_addStyle ( " \
a.intercepted { \
background: lime; \
} \
" );
}
else {
/***** Page opened by JS in either a popup or new tab.
This was *most likely* done by us, using window.open.
*/
$(window).bind ("beforeunload", function (zEvent) {
//-- Allow time for the file dialog to actually open.
setTimeout ( function () {
/*-- Since the time it takes for the user to respond
to the File dialog can vary radically, use a confirm
to keep the File dialog open long enough for the user
to act.
*/
var doClose = confirm ("Close this window?");
if (doClose) {
window.close ();
}
},
444 // 0.444 seconds
);
} );
}
function interceptLink (index, node) {
var jNode = $(node);
jNode.click (openInNewTab);
jNode.addClass ("intercepted");
}
function openInNewTab (zEvent) {
//-- Optionally adjust the href here, if needed.
var targURL = this.href;
var newTab = window.open (targURL, "_blank");
//--- Stop the link from doing anything else.
zEvent.preventDefault ();
zEvent.stopPropagation ();
return false;
}
这篇关于下载时打开和关闭新标签页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!