Merge remote-tracking branch 'origin/pr/3345'

This commit is contained in:
Florian Bruhin 2017-12-06 06:51:03 +01:00
commit dcb4448594
7 changed files with 124 additions and 9 deletions

View File

@ -1083,7 +1083,7 @@ Syntax: +:session-save [*--current*] [*--quiet*] [*--force*] [*--only-active-win
Save a session. Save a session.
==== positional arguments ==== positional arguments
* +'name'+: The name of the session. If not given, the session configured in session_default_name is saved. * +'name'+: The name of the session. If not given, the session configured in session.default_name is saved.
==== optional arguments ==== optional arguments

View File

@ -222,7 +222,7 @@
|<<qt.highdpi,qt.highdpi>>|Turn on Qt HighDPI scaling. |<<qt.highdpi,qt.highdpi>>|Turn on Qt HighDPI scaling.
|<<scrolling.bar,scrolling.bar>>|Show a scrollbar. |<<scrolling.bar,scrolling.bar>>|Show a scrollbar.
|<<scrolling.smooth,scrolling.smooth>>|Enable smooth scrolling for web pages. |<<scrolling.smooth,scrolling.smooth>>|Enable smooth scrolling for web pages.
|<<session_default_name,session_default_name>>|Name of the session to save by default. |<<session.default_name,session.default_name>>|Name of the session to save by default.
|<<spellcheck.languages,spellcheck.languages>>|Languages to use for spell checking. |<<spellcheck.languages,spellcheck.languages>>|Languages to use for spell checking.
|<<statusbar.hide,statusbar.hide>>|Hide the statusbar unless a message is shown. |<<statusbar.hide,statusbar.hide>>|Hide the statusbar unless a message is shown.
|<<statusbar.padding,statusbar.padding>>|Padding (in pixels) for the statusbar. |<<statusbar.padding,statusbar.padding>>|Padding (in pixels) for the statusbar.
@ -2556,8 +2556,8 @@ Type: <<types,Bool>>
Default: +pass:[false]+ Default: +pass:[false]+
[[session_default_name]] [[session.default_name]]
=== session_default_name === session.default_name
Name of the session to save by default. Name of the session to save by default.
If this is set to null, the session which was last loaded is saved. If this is set to null, the session which was last loaded is saved.

View File

@ -29,6 +29,7 @@ import os
import time import time
import textwrap import textwrap
import mimetypes import mimetypes
import urllib
import pkg_resources import pkg_resources
from PyQt5.QtCore import QUrlQuery, QUrl from PyQt5.QtCore import QUrlQuery, QUrl
@ -425,6 +426,18 @@ def qute_settings(url):
return 'text/html', html return 'text/html', html
@add_handler('back')
def qute_back(url):
"""Handler for qute://back.
Simple page to free ram / lazy load a site, goes back on focusing the tab.
"""
html = jinja.render(
'back.html',
title='Suspended: ' + urllib.parse.unquote(url.fragment()))
return 'text/html', html
@add_handler('configdiff') @add_handler('configdiff')
def qute_configdiff(url): def qute_configdiff(url):
"""Handler for qute://configdiff.""" """Handler for qute://configdiff."""

View File

@ -79,6 +79,9 @@ new_instance_open_target_window:
When `new_instance_open_target` is not set to `window`, this is ignored. When `new_instance_open_target` is not set to `window`, this is ignored.
session_default_name: session_default_name:
renamed: session.default_name
session.default_name:
type: type:
name: SessionName name: SessionName
none_ok: true none_ok: true
@ -88,6 +91,11 @@ session_default_name:
If this is set to null, the session which was last loaded is saved. If this is set to null, the session which was last loaded is saved.
session.lazy_restore:
type: Bool
default: false
desc: Load a restored tab as soon as it takes focus.
backend: backend:
type: type:
name: String name: String

View File

@ -0,0 +1,60 @@
{% extends "base.html" %}
{% block script %}
const STATE_BACK = "back";
const STATE_FORWARD = "forward";
function switch_state(new_state) {
history.replaceState(
new_state,
document.title,
location.pathname + location.hash);
}
function go_back() {
switch_state(STATE_FORWARD);
history.back();
}
function go_forward() {
switch_state(STATE_BACK);
history.forward();
}
function prepare_restore() {
if (!document.hidden) {
go_back();
return;
}
document.addEventListener("visibilitychange", go_back);
}
// there are three states
// default: register focus listener,
// on focus: go back and switch to the state forward
// back: user came from a later history entry
// -> switch to the state forward,
// forward him to the previous history entry
// forward: user came from a previous history entry
// -> switch to the state back,
// forward him to the next history entry
switch (history.state) {
case STATE_BACK:
go_back();
break;
case STATE_FORWARD:
go_forward();
break;
default:
setTimeout(prepare_restore, 1000);
break;
}
{% endblock %}
{% block content %}
<noscript><p>Javascript isn't enabled. So you need to manually go back in history to restore this tab.</p></noscript>
<p>Loading suspended page...<br>
<br>
If nothing happens, something went wrong or you disabled JavaScript.</p>
{% endblock %}

View File

@ -21,6 +21,8 @@
import os import os
import os.path import os.path
import itertools
import urllib
import sip import sip
from PyQt5.QtCore import QUrl, QObject, QPoint, QTimer from PyQt5.QtCore import QUrl, QObject, QPoint, QTimer
@ -205,7 +207,13 @@ class SessionManager(QObject):
for idx, item in enumerate(tab.history): for idx, item in enumerate(tab.history):
qtutils.ensure_valid(item) qtutils.ensure_valid(item)
item_data = self._save_tab_item(tab, idx, item) item_data = self._save_tab_item(tab, idx, item)
data['history'].append(item_data) if item.url().scheme() == 'qute' and item.url().host() == 'back':
# don't add qute://back to the session file
if item_data.get('active', False) and data['history']:
# mark entry before qute://back as active
data['history'][-1]['active'] = True
else:
data['history'].append(item_data)
return data return data
def _save_all(self, *, only_window=None, with_private=False): def _save_all(self, *, only_window=None, with_private=False):
@ -251,7 +259,7 @@ class SessionManager(QObject):
object. object.
""" """
if name is default: if name is default:
name = config.val.session_default_name name = config.val.session.default_name
if name is None: if name is None:
if self._current is not None: if self._current is not None:
name = self._current name = self._current
@ -323,7 +331,18 @@ class SessionManager(QObject):
def _load_tab(self, new_tab, data): def _load_tab(self, new_tab, data):
"""Load yaml data into a newly opened tab.""" """Load yaml data into a newly opened tab."""
entries = [] entries = []
for histentry in data['history']: lazy_load = []
# use len(data['history'])
# -> dropwhile empty if not session.lazy_session
lazy_index = len(data['history'])
gen = itertools.chain(
itertools.takewhile(lambda _: not lazy_load,
enumerate(data['history'])),
enumerate(lazy_load),
itertools.dropwhile(lambda i: i[0] < lazy_index,
enumerate(data['history'])))
for i, histentry in gen:
user_data = {} user_data = {}
if 'zoom' in data: if 'zoom' in data:
@ -347,6 +366,20 @@ class SessionManager(QObject):
if 'pinned' in histentry: if 'pinned' in histentry:
new_tab.data.pinned = histentry['pinned'] new_tab.data.pinned = histentry['pinned']
if (config.val.session.lazy_restore and
histentry.get('active', False) and
not histentry['url'].startswith('qute://back')):
# remove "active" mark and insert back page marked as active
lazy_index = i + 1
lazy_load.append({
'title': histentry['title'],
'url':
'qute://back#' +
urllib.parse.quote(histentry['title']),
'active': True
})
histentry['active'] = False
active = histentry.get('active', False) active = histentry.get('active', False)
url = QUrl.fromEncoded(histentry['url'].encode('ascii')) url = QUrl.fromEncoded(histentry['url'].encode('ascii'))
if 'original-url' in histentry: if 'original-url' in histentry:
@ -360,6 +393,7 @@ class SessionManager(QObject):
entries.append(entry) entries.append(entry)
if active: if active:
new_tab.title_changed.emit(histentry['title']) new_tab.title_changed.emit(histentry['title'])
try: try:
new_tab.history.load_items(entries) new_tab.history.load_items(entries)
except ValueError as e: except ValueError as e:
@ -460,7 +494,7 @@ class SessionManager(QObject):
Args: Args:
name: The name of the session. If not given, the session configured name: The name of the session. If not given, the session configured
in session_default_name is saved. in session.default_name is saved.
current: Save the current session instead of the default. current: Save the current session instead of the default.
quiet: Don't show confirmation message. quiet: Don't show confirmation message.
force: Force saving internal sessions (starting with an underline). force: Force saving internal sessions (starting with an underline).

View File

@ -170,7 +170,7 @@ class TestSaveAll:
]) ])
def test_get_session_name(config_stub, sess_man, arg, config, current, def test_get_session_name(config_stub, sess_man, arg, config, current,
expected): expected):
config_stub.val.session_default_name = config config_stub.val.session.default_name = config
sess_man._current = current sess_man._current = current
assert sess_man._get_session_name(arg) == expected assert sess_man._get_session_name(arg) == expected