Merge pull request #3080 from atom/save-page-api
Implement webContents.savePage API.
This commit is contained in:
Коммит
0e94ccb72b
|
@ -11,6 +11,7 @@
|
|||
#include "atom/browser/api/atom_api_download_item.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
|
@ -237,6 +238,8 @@ Session::~Session() {
|
|||
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
auto web_contents = item->GetWebContents();
|
||||
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
|
||||
return;
|
||||
bool prevent_default = Emit(
|
||||
"will-download",
|
||||
DownloadItem::Create(isolate(), item),
|
||||
|
|
|
@ -162,6 +162,26 @@ struct Converter<net::HttpResponseHeaders*> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<content::SavePageType> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
content::SavePageType* out) {
|
||||
std::string save_type;
|
||||
if (!ConvertFromV8(isolate, val, &save_type))
|
||||
return false;
|
||||
if (save_type == "HTMLOnly") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
|
||||
} else if (save_type == "HTMLComplete") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
|
||||
} else if (save_type == "MHTML") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_MHTML;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
|
||||
|
@ -665,6 +685,13 @@ void WebContents::InsertCSS(const std::string& css) {
|
|||
web_contents()->InsertCSS(css);
|
||||
}
|
||||
|
||||
bool WebContents::SavePage(const base::FilePath& full_file_path,
|
||||
const content::SavePageType& save_type,
|
||||
const SavePageHandler::SavePageCallback& callback) {
|
||||
auto handler = new SavePageHandler(web_contents(), callback);
|
||||
return handler->Handle(full_file_path, save_type);
|
||||
}
|
||||
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture) {
|
||||
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
|
||||
|
@ -976,6 +1003,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
|||
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
|
||||
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
|
||||
.SetMethod("insertCSS", &WebContents::InsertCSS)
|
||||
.SetMethod("savePage", &WebContents::SavePage)
|
||||
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
|
||||
.SetMethod("openDevTools", &WebContents::OpenDevTools)
|
||||
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/frame_subscriber.h"
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
|
@ -73,6 +74,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void SetUserAgent(const std::string& user_agent);
|
||||
std::string GetUserAgent();
|
||||
void InsertCSS(const std::string& css);
|
||||
bool SavePage(const base::FilePath& full_file_path,
|
||||
const content::SavePageType& save_type,
|
||||
const SavePageHandler::SavePageCallback& callback);
|
||||
void ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture);
|
||||
void OpenDevTools(mate::Arguments* args);
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
SavePageHandler::SavePageHandler(content::WebContents* web_contents,
|
||||
const SavePageCallback& callback)
|
||||
: web_contents_(web_contents),
|
||||
callback_(callback) {
|
||||
}
|
||||
|
||||
SavePageHandler::~SavePageHandler() {
|
||||
}
|
||||
|
||||
void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
// OnDownloadCreated is invoked during WebContents::SavePage, so the |item|
|
||||
// here is the one stated by WebContents::SavePage.
|
||||
item->AddObserver(this);
|
||||
}
|
||||
|
||||
bool SavePageHandler::Handle(const base::FilePath& full_path,
|
||||
const content::SavePageType& save_type) {
|
||||
auto download_manager = content::BrowserContext::GetDownloadManager(
|
||||
web_contents_->GetBrowserContext());
|
||||
download_manager->AddObserver(this);
|
||||
bool result = web_contents_->SavePage(full_path,
|
||||
full_path.DirName(),
|
||||
save_type);
|
||||
download_manager->RemoveObserver(this);
|
||||
// If initialization fails which means fail to create |DownloadItem|, we need
|
||||
// to delete the |SavePageHandler| instance to avoid memory-leak.
|
||||
if (!result)
|
||||
delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SavePageHandler::OnDownloadUpdated(content::DownloadItem* item) {
|
||||
if (item->IsDone()) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
if (item->GetState() == content::DownloadItem::COMPLETE) {
|
||||
callback_.Run(v8::Null(isolate));
|
||||
} else {
|
||||
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(
|
||||
isolate, "Fail to save page");
|
||||
callback_.Run(v8::Exception::Error(error_message));
|
||||
}
|
||||
Destroy(item);
|
||||
}
|
||||
}
|
||||
|
||||
void SavePageHandler::Destroy(content::DownloadItem* item) {
|
||||
item->RemoveObserver(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
// static
|
||||
bool SavePageHandler::IsSavePageTypes(const std::string& type) {
|
||||
return type == "multipart/related" || type == "text/html";
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||
#define ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "content/public/browser/download_item.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/save_page_type.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
// A self-destroyed class for handling save page request.
|
||||
class SavePageHandler : public content::DownloadManager::Observer,
|
||||
public content::DownloadItem::Observer {
|
||||
public:
|
||||
using SavePageCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
|
||||
SavePageHandler(content::WebContents* web_contents,
|
||||
const SavePageCallback& callback);
|
||||
~SavePageHandler();
|
||||
|
||||
bool Handle(const base::FilePath& full_path,
|
||||
const content::SavePageType& save_type);
|
||||
|
||||
static bool IsSavePageTypes(const std::string& type);
|
||||
|
||||
private:
|
||||
void Destroy(content::DownloadItem* item);
|
||||
|
||||
// content::DownloadManager::Observer:
|
||||
void OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) override;
|
||||
|
||||
// content::DownloadItem::Observer:
|
||||
void OnDownloadUpdated(content::DownloadItem* item) override;
|
||||
|
||||
content::WebContents* web_contents_; // weak
|
||||
SavePageCallback callback_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
|
@ -631,3 +631,26 @@ Get the `WebContents` of DevTools for this `WebContents`.
|
|||
|
||||
**Note:** Users should never store this object because it may become `null`
|
||||
when the DevTools has been closed.
|
||||
|
||||
### `webContents.savePage(fullPath, saveType, callback)`
|
||||
|
||||
* `fullPath` String - The full file path.
|
||||
* `saveType` String - Specify the save type.
|
||||
* `HTMLOnly` - Save only the HTML of the page.
|
||||
* `HTMLComplete` - Save complete-html page.
|
||||
* `MHTML` - Save complete-html page as MHTML.
|
||||
* `callback` Function - `function(error) {}`.
|
||||
* `error` Error
|
||||
|
||||
Returns true if the process of saving page has been initiated successfully.
|
||||
|
||||
```javascript
|
||||
win.loadUrl('https://github.com');
|
||||
|
||||
win.webContents.on('did-finish-load', function() {
|
||||
win.webContents.savePage('/tmp/test.html', 'HTMLComplete', function(error) {
|
||||
if (!error)
|
||||
console.log("Save page successfully");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
|
|
@ -108,6 +108,8 @@
|
|||
'atom/browser/api/trackable_object.h',
|
||||
'atom/browser/api/frame_subscriber.cc',
|
||||
'atom/browser/api/frame_subscriber.h',
|
||||
'atom/browser/api/save_page_handler.cc',
|
||||
'atom/browser/api/save_page_handler.h',
|
||||
'atom/browser/auto_updater.cc',
|
||||
'atom/browser/auto_updater.h',
|
||||
'atom/browser/auto_updater_delegate.h',
|
||||
|
|
|
@ -301,3 +301,15 @@ describe 'browser-window module', ->
|
|||
assert.notEqual data.length, 0
|
||||
w.webContents.endFrameSubscription()
|
||||
done()
|
||||
|
||||
describe 'save page', ->
|
||||
savePagePath = path.join fixtures, 'save_page.html'
|
||||
it 'should save page', (done) ->
|
||||
w.webContents.on 'did-finish-load', ->
|
||||
w.webContents.savePage savePagePath, 'HTMLComplete', (error) ->
|
||||
assert.equal error, null
|
||||
assert fs.existsSync savePagePath
|
||||
fs.unlinkSync savePagePath
|
||||
done()
|
||||
|
||||
w.loadUrl "file://#{fixtures}/api/blank.html"
|
||||
|
|
Загрузка…
Ссылка в новой задаче