Skip to content

Commit 2d19b6b

Browse files
tw4lkrakan
andauthored
Merge 2.7.1 development branch (#785)
* Add locale-dependent handling of first day of week The Intl.Locale is a proposed standard not yet supported by Firefox so in Firefox the first day of week will default to Monday (as specified in ISO-8601). * Set top frame document title when Vue updates * Update template guide for 2.7 * Drop Python 3.6 and add 3.10 in test CI * Allow either JS mimetype in test_add_static * Add convenience build script for Vue UI * Add build flag to docker compose example * Fix Vue app issue with redirect_to_exact: false Fixes #779 Undated URLs were resulting in a broken calendar and timeline in the Vue app when redirect_to_exact was set to false. This was due to TopFrameView using the current datetime if no timestamp was included, which caused a failed snapshot lookup in the Vue app. This commit changes the default timestamp in TopFrameView to None and adds additional logic in the Vue app to use the last snapshot's timestamp as the default if one is not present to match the snapshot that pywb loads by default under the same conditions. * Add filter instead of submitting form when pressing enter in the filtering expression field * Make filter expressions translatable * Add missing tooltip strings to vue_loc * Add changelog * Bump version to 2.7.1 * Use empty string as default template timestamp * Bump wombat to 3.3.13 Co-authored-by: Jonas Linde <jonasjlinde@gmail.com>
1 parent 6cc9cdc commit 2d19b6b

19 files changed

+168
-80
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
strategy:
99
max-parallel: 3
1010
matrix:
11-
python-version: [3.6, 3.7, 3.8, 3.9]
11+
python-version: ['3.7', '3.8', '3.9', '3.10']
1212

1313
steps:
1414
- name: checkout

CHANGES.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
pywb 2.7.1 changelist
2+
~~~~~~~~~~~~~~~~~~~~~
3+
4+
* Add locale-dependent handling of first day of week by @krakan in https://github.com/webrecorder/pywb/pull/781
5+
* Make filter expressions translatable by @krakan in https://github.com/webrecorder/pywb/pull/783
6+
* Add title to top frame in framed replay
7+
* Add missing tooltip translation strings
8+
* Fix calendar and timeline rendering for replay URLs without a timestamp
9+
* Update template documentation
10+
111
pywb 2.7.0 changelist
212
~~~~~~~~~~~~~~~~~~~~~
313

CONTRIBUTING.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,11 @@ The first time you run this command, it make take some time to build.
5151
Changes to the [Vue](https://vuejs.org/) frontend components require rebuilding the Vue bundle (`pywb/static/vue/vueui.js`) to take effect. After making changes to one or more Vue components, you can rebuild the static bundle and view the changes in your development environment like so:
5252

5353
```bash
54-
cd pywb/vueui
55-
yarn run build
56-
cd ../..
57-
docker compose up -d --force-recreate
54+
./build-vue-ui.sh
55+
docker compose up -d --build --force-recreate
5856
```
5957

60-
Changes that modify pywb's Python dependencies or the operating system may require rebuilding the container:
58+
Changes that modify pywb's Python dependencies or the operating system also require rebuilding the container:
6159

6260
```bash
6361
docker compose up -d --build --force-recreate

build-vue-ui.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
3+
CURR_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4+
5+
cd $CURR_DIR/pywb/vueui/
6+
yarn run build

docs/manual/template-guide.rst

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ Base Templates (and supporting templates)
4848

4949
File: ``base.html``
5050

51-
This template includes the HTML added to all other pages, replay and non-replay. Shared JS and CSS includes can be added here.
52-
For theming all pywb UI, it may be useful to modify this template.
51+
This template includes the HTML added to all pages other than framed replay. Shared JS and CSS includes meant for pages other than framed replay can be added here.
5352

5453
To customize the default pywb UI across multiple pages, the following additional templates
5554
can also be overriden:
@@ -61,7 +60,7 @@ can also be overriden:
6160
* ``footer.html`` -- Template for adding content as the "footer" of the ``<body>`` tag of the ``base`` template
6261

6362

64-
Note: The default pywb ``head.html`` and ``footer.html`` are currently blank. They can be populated to customize the rendering, add analytics, etc... as needed.
63+
Note: The default pywb ``head.html`` and ``footer.html`` are currently blank. They can be populated to customize the rendering, add analytics, etc... as needed. Content such as styles or JS code (for example for analytics) must be added to the ``frame_insert.html`` template as well (details on that template below) to also be included in framed replay.
6564

6665

6766
The ``base.html`` template also provides five blocks that can be supplied by templates that extend it.
@@ -172,9 +171,7 @@ Banner Template
172171

173172
File: ``banner.html``
174173

175-
This template is used to render the banner and is used both in framed replay and frameless replay.
176-
177-
In framed replay, the template is only rendered in the top/outer frame, while in frameless replay, it is added to every page.
174+
This template is used to render the banner for framed replay. It is rendered only rendered in the top/outer frame.
178175

179176
Template variables:
180177

@@ -192,7 +189,17 @@ Template variables:
192189

193190
* ``{{ ui }}`` - an optional ``ui`` dictionary from ``config.yaml``, if any.
194191

195-
The default banner creates the UI dynamically in JavaScript using Vue.
192+
The default banner creates the UI dynamically in JavaScript using Vue in the ``frame_insert.html`` template.
193+
194+
195+
Custom Banner Template
196+
^^^^^^^^^^^^^^^^^^^^^^
197+
198+
File: ``custom_banner.html``
199+
200+
This template can be used to render a custom banner for frameless replay. It is blank by default.
201+
202+
In frameless replay, the content of this template is injected into the ``head_insert.html`` template to render the banner.
196203

197204

198205
Head Insert Template
@@ -204,7 +211,7 @@ This template represents the HTML injected into every replay page to add support
204211

205212
This template is part of the core pywb replay, and modifying this template is not recommended.
206213

207-
For customizing the banner, modify the ``banner.html`` template instead.
214+
For customizing the banner, modify the ``banner.html`` (framed replay) or ``custom_banner.html`` (frameless replay) template instead.
208215

209216

210217
Top Frame Template
@@ -221,16 +228,21 @@ This template is responsible for creating the iframe that will render the conten
221228
This template only renders the banner and is designed *not* to set the encoding to allow the browser to 'detect' the encoding for the containing iframe.
222229
For this reason, the template should only contain ASCII text, and %-encode any non-ASCII characters.
223230

231+
Content such as analytics code that is desired in the top frame of framed replay pages should be added to this template.
232+
224233
Template variables:
225234

226235
* ``{{ url }}`` - the URL being replayed.
227236

237+
* ``{{ timestamp }}`` - the timestamp being replayed, e.g. ``20211226`` in ``http://localhost:8080/pywb/20211226/mp_/https://example.com/``
238+
228239
* ``{{ wb_url }}`` - A complete ``WbUrl`` object, which contains the ``url``, ``timestamp`` and ``mod`` properties, representing the replay url.
229240

230241
* ``{{ wb_prefix }}`` - the collection prefix, e.g. ``http://localhost:8080/pywb/``
231242

232243
* ``{{ is_proxy }}`` - set to true if page is being loaded via an HTTP/S proxy (checks if WSGI env has ``wsgiprox.proxy_host`` set)
233244

245+
* ``{{ ui }}`` - an optional ``ui`` dictionary from ``config.yaml``, if any.
234246

235247

236248
.. _custom-top-frame:

pywb/rewrite/templateview.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,10 +405,9 @@ def get_top_frame(self, wb_url,
405405

406406
embed_url = wb_url.to_str(mod=replay_mod)
407407

408+
timestamp = ''
408409
if wb_url.timestamp:
409410
timestamp = wb_url.timestamp
410-
else:
411-
timestamp = timestamp_now()
412411

413412
is_proxy = 'wsgiprox.proxy_host' in env
414413

pywb/static/query.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,6 @@ function RenderCalendar(init) {
5757
};
5858
// regex for extracting the filter constraints and filter mods to human explanation
5959
this.filterRE = /filter([^a-z]+)([a-z]+):(.+)/i;
60-
this.filterMods = {
61-
'=': 'Contains',
62-
'==': 'Matches Exactly',
63-
'=~': 'Matches Regex',
64-
'=!': 'Does Not Contains',
65-
'=!=': 'Is Not',
66-
'=!~': 'Does Not Begins With'
67-
};
6860
this.text = init.text;
6961
this.versionString = null;
7062
}
@@ -433,7 +425,6 @@ RenderCalendar.prototype.createContainers = function() {
433425
return;
434426
}
435427
// create the advanced results query info DOM structure
436-
var forString = ' for ';
437428
var forElems;
438429

439430
if (this.queryInfo.searchParams.matchType) {
@@ -503,7 +494,7 @@ RenderCalendar.prototype.createContainers = function() {
503494
{
504495
tag: 'p',
505496
className: 'text-center mb-0 mt-1',
506-
innerText: 'Filtering by'
497+
innerText: filteringBy
507498
},
508499
{
509500
tag: 'ul',
@@ -950,7 +941,7 @@ RenderCalendar.prototype.niceFilterDisplay = function() {
950941
filterList.push({
951942
tag: 'li',
952943
className: 'list-group-item',
953-
innerText: match[2] + ' ' + this.filterMods[match[1]] + ' ' + match[3]
944+
innerText: match[2] + ' ' + filterMods[match[1]] + ' "' + match[3] + '"'
954945
});
955946
}
956947
}

pywb/static/search.js

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
var dtRE = /^\d{4,14}$/;
22
var didSetWasValidated = false;
33
var showBadDateTimeClass = 'show-optional-bad-input';
4-
var filterMods = {
5-
'=': 'Contains',
6-
'==': 'Matches Exactly',
7-
'=~': 'Matches Regex',
8-
'=!': 'Does Not Contains',
9-
'=!=': 'Is Not',
10-
'=!~': 'Does Not Begins With'
11-
};
124

135
var elemIds = {
146
filtering: {
@@ -65,7 +57,7 @@ function makeCheckDateRangeChecker(dtInputId, dtBadNotice) {
6557

6658
function createAndAddNoFilter(filterList) {
6759
var nothing = document.createElement('li');
68-
nothing.innerText = 'No Filter';
60+
nothing.innerText = noFilter;
6961
nothing.id = elemIds.filtering.nothing;
7062
filterList.appendChild(nothing);
7163
}
@@ -78,19 +70,24 @@ function addFilter(event) {
7870
if (!expr) return;
7971
var filterExpr = 'filter' + modifier + by + ':' + expr;
8072
var filterList = document.getElementById(elemIds.filtering.list);
73+
var previousFilters = filterList.children;
74+
for (var i = 0; i < previousFilters.length; ++i) {
75+
var filterData = previousFilters[i].dataset;
76+
if (filterData && filterData.filter && filterData.filter == filterExpr) return;
77+
}
8178
var filterNothing = document.getElementById(elemIds.filtering.nothing);
8279
if (filterNothing) {
8380
filterList.removeChild(filterNothing);
8481
}
8582
var li = document.createElement('li');
8683
li.innerText =
87-
'By ' +
8884
by[0].toUpperCase() +
8985
by.substr(1) +
9086
' ' +
9187
filterMods[modifier] +
92-
' ' +
93-
expr;
88+
' "' +
89+
expr +
90+
'"';
9491
li.dataset.filter = filterExpr;
9592
var nukeButton = document.createElement('button');
9693
nukeButton.type = 'button';
@@ -110,6 +107,7 @@ function addFilter(event) {
110107
};
111108
li.appendChild(nukeButton);
112109
filterList.appendChild(li);
110+
return true;
113111
}
114112

115113
function clearFilters(event) {
@@ -166,6 +164,17 @@ function validateFields(form) {
166164
}
167165
}
168166

167+
function submitForm(event, form, searchURLInput) {
168+
event.preventDefault();
169+
event.stopPropagation();
170+
var url = searchURLInput.value;
171+
if (!url) {
172+
validateFields(form);
173+
return;
174+
}
175+
performQuery(url);
176+
}
177+
169178
$(document).ready(function() {
170179
$('[data-toggle="tooltip"]').tooltip({
171180
container: 'body',
@@ -184,16 +193,18 @@ $(document).ready(function() {
184193
var searchURLInput = document.getElementById(elemIds.url);
185194
var form = document.getElementById(elemIds.form);
186195
form.addEventListener('submit', function(event) {
187-
event.preventDefault();
188-
event.stopPropagation();
189-
var url = searchURLInput.value;
190-
if (!url) {
191-
validateFields(form);
192-
return;
193-
}
194-
performQuery(url);
196+
submitForm(event, form, searchURLInput);
195197
});
196198
document.getElementById(elemIds.advancedOptions).onclick = function() {
197199
validateFields(form);
198200
}
201+
var filteringExpression = document.getElementById(elemIds.filtering.expression);
202+
filteringExpression.addEventListener("keypress", function(event) {
203+
if (event.key === "Enter") {
204+
event.preventDefault();
205+
if (! addFilter()) {
206+
submitForm(event, form, searchURLInput);
207+
}
208+
}
209+
});
199210
});

0 commit comments

Comments
 (0)