189 lines
5.8 KiB
JavaScript
189 lines
5.8 KiB
JavaScript
var NavigationController, ipcMain,
|
|
slice = [].slice;
|
|
|
|
ipcMain = require('electron').ipcMain;
|
|
|
|
// The history operation in renderer is redirected to browser.
|
|
ipcMain.on('ATOM_SHELL_NAVIGATION_CONTROLLER', function() {
|
|
var args, event, method, ref;
|
|
event = arguments[0], method = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
|
|
return (ref = event.sender)[method].apply(ref, args);
|
|
});
|
|
|
|
ipcMain.on('ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', function() {
|
|
var args, event, method, ref;
|
|
event = arguments[0], method = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
|
|
return event.returnValue = (ref = event.sender)[method].apply(ref, args);
|
|
});
|
|
|
|
// JavaScript implementation of Chromium's NavigationController.
|
|
// Instead of relying on Chromium for history control, we compeletely do history
|
|
// control on user land, and only rely on WebContents.loadURL for navigation.
|
|
// This helps us avoid Chromium's various optimizations so we can ensure renderer
|
|
// process is restarted everytime.
|
|
NavigationController = (function() {
|
|
function NavigationController(webContents) {
|
|
this.webContents = webContents;
|
|
this.clearHistory();
|
|
|
|
// webContents may have already navigated to a page.
|
|
if (this.webContents._getURL()) {
|
|
this.currentIndex++;
|
|
this.history.push(this.webContents._getURL());
|
|
}
|
|
this.webContents.on('navigation-entry-commited', (function(_this) {
|
|
return function(event, url, inPage, replaceEntry) {
|
|
var currentEntry;
|
|
if (_this.inPageIndex > -1 && !inPage) {
|
|
|
|
// Navigated to a new page, clear in-page mark.
|
|
_this.inPageIndex = -1;
|
|
} else if (_this.inPageIndex === -1 && inPage) {
|
|
|
|
// Started in-page navigations.
|
|
_this.inPageIndex = _this.currentIndex;
|
|
}
|
|
if (_this.pendingIndex >= 0) {
|
|
|
|
// Go to index.
|
|
_this.currentIndex = _this.pendingIndex;
|
|
_this.pendingIndex = -1;
|
|
return _this.history[_this.currentIndex] = url;
|
|
} else if (replaceEntry) {
|
|
|
|
// Non-user initialized navigation.
|
|
return _this.history[_this.currentIndex] = url;
|
|
} else {
|
|
|
|
// Normal navigation. Clear history.
|
|
_this.history = _this.history.slice(0, _this.currentIndex + 1);
|
|
currentEntry = _this.history[_this.currentIndex];
|
|
if ((currentEntry != null ? currentEntry.url : void 0) !== url) {
|
|
_this.currentIndex++;
|
|
return _this.history.push(url);
|
|
}
|
|
}
|
|
};
|
|
})(this));
|
|
}
|
|
|
|
NavigationController.prototype.loadURL = function(url, options) {
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
this.pendingIndex = -1;
|
|
this.webContents._loadURL(url, options);
|
|
return this.webContents.emit('load-url', url, options);
|
|
};
|
|
|
|
NavigationController.prototype.getURL = function() {
|
|
if (this.currentIndex === -1) {
|
|
return '';
|
|
} else {
|
|
return this.history[this.currentIndex];
|
|
}
|
|
};
|
|
|
|
NavigationController.prototype.stop = function() {
|
|
this.pendingIndex = -1;
|
|
return this.webContents._stop();
|
|
};
|
|
|
|
NavigationController.prototype.reload = function() {
|
|
this.pendingIndex = this.currentIndex;
|
|
return this.webContents._loadURL(this.getURL(), {});
|
|
};
|
|
|
|
NavigationController.prototype.reloadIgnoringCache = function() {
|
|
this.pendingIndex = this.currentIndex;
|
|
return this.webContents._loadURL(this.getURL(), {
|
|
extraHeaders: "pragma: no-cache\n"
|
|
});
|
|
};
|
|
|
|
NavigationController.prototype.canGoBack = function() {
|
|
return this.getActiveIndex() > 0;
|
|
};
|
|
|
|
NavigationController.prototype.canGoForward = function() {
|
|
return this.getActiveIndex() < this.history.length - 1;
|
|
};
|
|
|
|
NavigationController.prototype.canGoToIndex = function(index) {
|
|
return index >= 0 && index < this.history.length;
|
|
};
|
|
|
|
NavigationController.prototype.canGoToOffset = function(offset) {
|
|
return this.canGoToIndex(this.currentIndex + offset);
|
|
};
|
|
|
|
NavigationController.prototype.clearHistory = function() {
|
|
this.history = [];
|
|
this.currentIndex = -1;
|
|
this.pendingIndex = -1;
|
|
return this.inPageIndex = -1;
|
|
};
|
|
|
|
NavigationController.prototype.goBack = function() {
|
|
if (!this.canGoBack()) {
|
|
return;
|
|
}
|
|
this.pendingIndex = this.getActiveIndex() - 1;
|
|
if (this.inPageIndex > -1 && this.pendingIndex >= this.inPageIndex) {
|
|
return this.webContents._goBack();
|
|
} else {
|
|
return this.webContents._loadURL(this.history[this.pendingIndex], {});
|
|
}
|
|
};
|
|
|
|
NavigationController.prototype.goForward = function() {
|
|
if (!this.canGoForward()) {
|
|
return;
|
|
}
|
|
this.pendingIndex = this.getActiveIndex() + 1;
|
|
if (this.inPageIndex > -1 && this.pendingIndex >= this.inPageIndex) {
|
|
return this.webContents._goForward();
|
|
} else {
|
|
return this.webContents._loadURL(this.history[this.pendingIndex], {});
|
|
}
|
|
};
|
|
|
|
NavigationController.prototype.goToIndex = function(index) {
|
|
if (!this.canGoToIndex(index)) {
|
|
return;
|
|
}
|
|
this.pendingIndex = index;
|
|
return this.webContents._loadURL(this.history[this.pendingIndex], {});
|
|
};
|
|
|
|
NavigationController.prototype.goToOffset = function(offset) {
|
|
var pendingIndex;
|
|
if (!this.canGoToOffset(offset)) {
|
|
return;
|
|
}
|
|
pendingIndex = this.currentIndex + offset;
|
|
if (this.inPageIndex > -1 && pendingIndex >= this.inPageIndex) {
|
|
this.pendingIndex = pendingIndex;
|
|
return this.webContents._goToOffset(offset);
|
|
} else {
|
|
return this.goToIndex(pendingIndex);
|
|
}
|
|
};
|
|
|
|
NavigationController.prototype.getActiveIndex = function() {
|
|
if (this.pendingIndex === -1) {
|
|
return this.currentIndex;
|
|
} else {
|
|
return this.pendingIndex;
|
|
}
|
|
};
|
|
|
|
NavigationController.prototype.length = function() {
|
|
return this.history.length;
|
|
};
|
|
|
|
return NavigationController;
|
|
|
|
})();
|
|
|
|
module.exports = NavigationController;
|