feat: extend navigationHistory API (#42014)
* feat: extend navigationHistory API * refactor: simplify index checking * refactor: rename 'getHistory' and 'replaceHistory' methods of navigationHistory * refactor: rename delete*() methods to remove*() * feat: remove navigationHistory.replaceHistory() * tests: add tests for removeEntryAtIndex and getAllEntries
This commit is contained in:
parent
4c3014944c
commit
189675575c
8 changed files with 105 additions and 6 deletions
|
@ -35,10 +35,7 @@ Returns `Integer` - The index of the current page, from which we would go back/f
|
|||
|
||||
* `index` Integer
|
||||
|
||||
Returns `Object`:
|
||||
|
||||
* `url` string - The URL of the navigation entry at the given index.
|
||||
* `title` string - The page title of the navigation entry at the given index.
|
||||
Returns [`NavigationEntry`](structures/navigation-entry.md) - Navigation entry at the given index.
|
||||
|
||||
If index is out of bounds (greater than history length or less than 0), null will be returned.
|
||||
|
||||
|
@ -65,3 +62,15 @@ Navigates to the specified offset from the current entry.
|
|||
#### `navigationHistory.length()`
|
||||
|
||||
Returns `Integer` - History length.
|
||||
|
||||
#### `navigationHistory.removeEntryAtIndex(index)`
|
||||
|
||||
* `index` Integer
|
||||
|
||||
Removes the navigation entry at the given index. Can't remove entry at the "current active index".
|
||||
|
||||
Returns `boolean` - Whether the navigation entry was removed from the webContents history.
|
||||
|
||||
#### `navigationHistory.getAllEntries()`
|
||||
|
||||
Returns [`NavigationEntry[]`](structures/navigation-entry.md) - WebContents complete history.
|
||||
|
|
4
docs/api/structures/navigation-entry.md
Normal file
4
docs/api/structures/navigation-entry.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# NavigationEntry Object
|
||||
|
||||
* `url` string
|
||||
* `title` string
|
|
@ -105,6 +105,7 @@ auto_filenames = {
|
|||
"docs/api/structures/mime-typed-buffer.md",
|
||||
"docs/api/structures/mouse-input-event.md",
|
||||
"docs/api/structures/mouse-wheel-input-event.md",
|
||||
"docs/api/structures/navigation-entry.md",
|
||||
"docs/api/structures/notification-action.md",
|
||||
"docs/api/structures/notification-response.md",
|
||||
"docs/api/structures/open-external-permission-request.md",
|
||||
|
|
|
@ -595,7 +595,9 @@ WebContents.prototype._init = function () {
|
|||
goToOffset: this._goToOffset.bind(this),
|
||||
getActiveIndex: this._getActiveIndex.bind(this),
|
||||
length: this._historyLength.bind(this),
|
||||
getEntryAtIndex: this._getNavigationEntryAtIndex.bind(this)
|
||||
getEntryAtIndex: this._getNavigationEntryAtIndex.bind(this),
|
||||
removeEntryAtIndex: this._removeNavigationEntryAtIndex.bind(this),
|
||||
getAllEntries: this._getHistory.bind(this)
|
||||
},
|
||||
writable: false,
|
||||
enumerable: true
|
||||
|
|
|
@ -2496,6 +2496,31 @@ content::NavigationEntry* WebContents::GetNavigationEntryAtIndex(
|
|||
return web_contents()->GetController().GetEntryAtIndex(index);
|
||||
}
|
||||
|
||||
bool WebContents::RemoveNavigationEntryAtIndex(int index) {
|
||||
if (!CanGoToIndex(index))
|
||||
return false;
|
||||
|
||||
return web_contents()->GetController().RemoveEntryAtIndex(index);
|
||||
}
|
||||
|
||||
std::vector<content::NavigationEntry*> WebContents::GetHistory() const {
|
||||
const int history_length = GetHistoryLength();
|
||||
auto& controller = web_contents()->GetController();
|
||||
|
||||
// If the history is empty, it contains only one entry and that is
|
||||
// "InitialEntry"
|
||||
if (history_length == 1 && controller.GetEntryAtIndex(0)->IsInitialEntry())
|
||||
return std::vector<content::NavigationEntry*>();
|
||||
|
||||
std::vector<content::NavigationEntry*> history;
|
||||
history.reserve(history_length);
|
||||
|
||||
for (int i = 0; i < history_length; i++)
|
||||
history.push_back(controller.GetEntryAtIndex(i));
|
||||
|
||||
return history;
|
||||
}
|
||||
|
||||
void WebContents::ClearHistory() {
|
||||
// In some rare cases (normally while there is no real history) we are in a
|
||||
// state where we can't prune navigation entries
|
||||
|
@ -4295,6 +4320,9 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
|
|||
.SetMethod("_getNavigationEntryAtIndex",
|
||||
&WebContents::GetNavigationEntryAtIndex)
|
||||
.SetMethod("_historyLength", &WebContents::GetHistoryLength)
|
||||
.SetMethod("_removeNavigationEntryAtIndex",
|
||||
&WebContents::RemoveNavigationEntryAtIndex)
|
||||
.SetMethod("_getHistory", &WebContents::GetHistory)
|
||||
.SetMethod("_clearHistory", &WebContents::ClearHistory)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
.SetMethod("forcefullyCrashRenderer",
|
||||
|
|
|
@ -204,6 +204,8 @@ class WebContents : public ExclusiveAccessContext,
|
|||
void GoToIndex(int index);
|
||||
int GetActiveIndex() const;
|
||||
content::NavigationEntry* GetNavigationEntryAtIndex(int index) const;
|
||||
bool RemoveNavigationEntryAtIndex(int index);
|
||||
std::vector<content::NavigationEntry*> GetHistory() const;
|
||||
void ClearHistory();
|
||||
int GetHistoryLength() const;
|
||||
const std::string GetWebRTCIPHandlingPolicy() const;
|
||||
|
|
|
@ -567,6 +567,39 @@ describe('webContents module', () => {
|
|||
w = new BrowserWindow({ show: false });
|
||||
});
|
||||
afterEach(closeAllWindows);
|
||||
describe('navigationHistory.removeEntryAtIndex(index) API', () => {
|
||||
it('should remove a navigation entry given a valid index', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
await w.loadURL(urlPage2);
|
||||
await w.loadURL(urlPage3);
|
||||
const initialLength = w.webContents.navigationHistory.length();
|
||||
const wasRemoved = w.webContents.navigationHistory.removeEntryAtIndex(1); // Attempt to remove the second entry
|
||||
const newLength = w.webContents.navigationHistory.length();
|
||||
expect(wasRemoved).to.be.true();
|
||||
expect(newLength).to.equal(initialLength - 1);
|
||||
});
|
||||
|
||||
it('should not remove the current active navigation entry', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
await w.loadURL(urlPage2);
|
||||
const activeIndex = w.webContents.navigationHistory.getActiveIndex();
|
||||
const wasRemoved = w.webContents.navigationHistory.removeEntryAtIndex(activeIndex);
|
||||
expect(wasRemoved).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false given an invalid index larger than history length', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
const wasRemoved = w.webContents.navigationHistory.removeEntryAtIndex(5); // Index larger than history length
|
||||
expect(wasRemoved).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false given an invalid negative index', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
const wasRemoved = w.webContents.navigationHistory.removeEntryAtIndex(-1); // Negative index
|
||||
expect(wasRemoved).to.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
describe('navigationHistory.canGoBack and navigationHistory.goBack API', () => {
|
||||
it('should not be able to go back if history is empty', async () => {
|
||||
expect(w.webContents.navigationHistory.canGoBack()).to.be.false();
|
||||
|
@ -706,6 +739,24 @@ describe('webContents module', () => {
|
|||
expect(w.webContents.navigationHistory.length()).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('navigationHistory.getAllEntries() API', () => {
|
||||
it('should return all navigation entries as an array of NavigationEntry objects', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
await w.loadURL(urlPage2);
|
||||
await w.loadURL(urlPage3);
|
||||
const entries = w.webContents.navigationHistory.getAllEntries();
|
||||
expect(entries.length).to.equal(3);
|
||||
expect(entries[0]).to.deep.equal({ url: urlPage1, title: 'Page 1' });
|
||||
expect(entries[1]).to.deep.equal({ url: urlPage2, title: 'Page 2' });
|
||||
expect(entries[2]).to.deep.equal({ url: urlPage3, title: 'Page 3' });
|
||||
});
|
||||
|
||||
it('should return an empty array when there is no navigation history', async () => {
|
||||
const entries = w.webContents.navigationHistory.getAllEntries();
|
||||
expect(entries.length).to.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFocusedWebContents() API', () => {
|
||||
|
|
4
typings/internal-electron.d.ts
vendored
4
typings/internal-electron.d.ts
vendored
|
@ -87,7 +87,7 @@ declare namespace Electron {
|
|||
_print(options: any, callback?: (success: boolean, failureReason: string) => void): void;
|
||||
_getPrintersAsync(): Promise<Electron.PrinterInfo[]>;
|
||||
_init(): void;
|
||||
_getNavigationEntryAtIndex(index: number): Electron.EntryAtIndex | null;
|
||||
_getNavigationEntryAtIndex(index: number): Electron.NavigationEntry | null;
|
||||
_getActiveIndex(): number;
|
||||
_historyLength(): number;
|
||||
_canGoBack(): boolean;
|
||||
|
@ -97,6 +97,8 @@ declare namespace Electron {
|
|||
_goForward(): void;
|
||||
_goToOffset(index: number): void;
|
||||
_goToIndex(index: number): void;
|
||||
_removeNavigationEntryAtIndex(index: number): boolean;
|
||||
_getHistory(): Electron.NavigationEntry[];
|
||||
_clearHistory():void
|
||||
canGoToIndex(index: number): boolean;
|
||||
destroy(): void;
|
||||
|
|
Loading…
Reference in a new issue