@internetarchive/ia-book-actions 1.4.3-alpha-adminsticky → 1.4.3-alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/pr-preview.yml +0 -4
- package/index.html +397 -118
- package/package.json +2 -2
- package/src/assets/data/info.js +12 -0
- package/src/core/services/actions-handler/actions-handler-service.js +5 -1
- package/src/core/services/actions-handler/actions-handler.js +5 -5
- package/src/core/services/loan-analytics.js +1 -1
- package/src/core/services/loan-renew-helper.js +2 -3
- package/src/ia-book-actions.js +222 -221
- package/test/core/services/loan-renew-helper.test.js +1 -1
- package/test/ia-book-actions.test.js +221 -7
- package/test/core/services/actions-handler.test.js +0 -91
package/index.html
CHANGED
|
@@ -38,11 +38,13 @@
|
|
|
38
38
|
|
|
39
39
|
fieldset {
|
|
40
40
|
width: fit-content;
|
|
41
|
+
max-width: 100%;
|
|
42
|
+
box-sizing: border-box;
|
|
41
43
|
margin-top: 50px;
|
|
42
44
|
}
|
|
43
45
|
fieldset legend {
|
|
44
46
|
text-align: left;
|
|
45
|
-
font-size:
|
|
47
|
+
font-size: 14px;
|
|
46
48
|
}
|
|
47
49
|
td {
|
|
48
50
|
color: white;
|
|
@@ -52,7 +54,7 @@
|
|
|
52
54
|
text-align: initial;
|
|
53
55
|
margin: 5px 0;
|
|
54
56
|
width: max-content;
|
|
55
|
-
display:
|
|
57
|
+
display: inline;
|
|
56
58
|
}
|
|
57
59
|
label {
|
|
58
60
|
padding: 10px;
|
|
@@ -83,9 +85,103 @@
|
|
|
83
85
|
border-radius: 10px;
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
.timer-presets {
|
|
89
|
+
display: flex;
|
|
90
|
+
gap: 6px;
|
|
91
|
+
flex-wrap: wrap;
|
|
92
|
+
max-width: 100%;
|
|
93
|
+
}
|
|
94
|
+
.timer-presets button {
|
|
95
|
+
padding: 6px 10px;
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
border: 2px solid #194880;
|
|
98
|
+
border-radius: 10px;
|
|
99
|
+
background: white;
|
|
100
|
+
}
|
|
101
|
+
.timer-presets button.active-preset {
|
|
102
|
+
background: #194880;
|
|
103
|
+
color: white;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
#live-status-wrapper {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
gap: 10px;
|
|
110
|
+
flex-wrap: wrap;
|
|
111
|
+
/* width: min(400px, 100%); */
|
|
112
|
+
|
|
113
|
+
/* display: flex; gap: 3rem; margin: 0 3rem; flex-wrap: wrap; */
|
|
114
|
+
}
|
|
115
|
+
#loan-status-row,
|
|
116
|
+
#lending-bar-controls {
|
|
117
|
+
display: grid;
|
|
118
|
+
grid-template-columns: repeat(2, 1fr);
|
|
119
|
+
gap: 3rem;
|
|
120
|
+
margin: 0 3rem;
|
|
121
|
+
}
|
|
122
|
+
@media (max-width: 700px) {
|
|
123
|
+
#loan-status-row,
|
|
124
|
+
#lending-bar-controls {
|
|
125
|
+
grid-template-columns: 1fr;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
.loan-status-badge {
|
|
129
|
+
display: inline-block;
|
|
130
|
+
padding: 8px 14px;
|
|
131
|
+
border-radius: 6px;
|
|
132
|
+
font-size: 14px;
|
|
133
|
+
font-weight: bold;
|
|
134
|
+
letter-spacing: 0.5px;
|
|
135
|
+
color: white;
|
|
136
|
+
}
|
|
137
|
+
.loan-status-badge.status-active {
|
|
138
|
+
background: #2e7d32; /* green: loan is currently checked out */
|
|
139
|
+
}
|
|
140
|
+
.loan-status-badge.status-returned {
|
|
141
|
+
background: #d9534f; /* red: auto-returned / not on loan */
|
|
142
|
+
}
|
|
143
|
+
.loan-status-badge.status-none {
|
|
144
|
+
background: #666; /* gray: nothing borrowed yet */
|
|
145
|
+
}
|
|
146
|
+
#live-status-detail {
|
|
147
|
+
color: white;
|
|
148
|
+
background: #333;
|
|
149
|
+
padding: 8px 12px;
|
|
150
|
+
border-radius: 6px;
|
|
151
|
+
font-size: 12px;
|
|
152
|
+
text-align: left;
|
|
153
|
+
flex: 1;
|
|
154
|
+
}
|
|
155
|
+
#exec-log {
|
|
156
|
+
text-align: left;
|
|
157
|
+
background: #111;
|
|
158
|
+
color: #9fef9f;
|
|
159
|
+
font-family: monospace;
|
|
160
|
+
font-size: 11px;
|
|
161
|
+
max-height: 160px;
|
|
162
|
+
overflow-y: auto;
|
|
163
|
+
padding: 8px;
|
|
164
|
+
border-radius: 6px;
|
|
165
|
+
margin-top: 8px;
|
|
166
|
+
white-space: pre-wrap;
|
|
167
|
+
word-break: break-word;
|
|
168
|
+
}
|
|
169
|
+
#exec-log div + div {
|
|
170
|
+
border-top: 1px solid #333;
|
|
171
|
+
padding-top: 2px;
|
|
172
|
+
margin-top: 2px;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#auto-renew-controls {
|
|
176
|
+
display: none1;
|
|
177
|
+
}
|
|
86
178
|
body.modal-manager-open {
|
|
87
179
|
overflow: hidden;
|
|
88
180
|
}
|
|
181
|
+
|
|
182
|
+
#action-bar-modal {
|
|
183
|
+
--modalWidth: 35rem;
|
|
184
|
+
}
|
|
89
185
|
|
|
90
186
|
modal-manager[mode='closed'] {
|
|
91
187
|
display: none;
|
|
@@ -96,6 +192,44 @@
|
|
|
96
192
|
<body>
|
|
97
193
|
<ia-book-actions></ia-book-actions>
|
|
98
194
|
|
|
195
|
+
<script>
|
|
196
|
+
/* eslint-disable */
|
|
197
|
+
// WEBDEV-8322: capture the library's `log()` lines — API calls
|
|
198
|
+
// (create_token/browse_book/borrow_book/renew_loan/return_loan and their
|
|
199
|
+
// success/error from ActionsHandlerService), lifecycle events
|
|
200
|
+
// ([IABookActions]: page-turn/BookReader:userAction received,
|
|
201
|
+
// visibilitychange backgrounded/foregrounded, browseHasExpired,
|
|
202
|
+
// showWarningModal, handleLoanAutoRenewed, etc), and anything the demo
|
|
203
|
+
// itself triggers ([Demo]: user_has_browsed set, error-mode toggled,
|
|
204
|
+
// etc) — into the live status panel below, so QA can see everything
|
|
205
|
+
// that happened without opening devtools. GA event-mirroring noise
|
|
206
|
+
// (`eventCategory:- ...`) is the one thing still filtered out.
|
|
207
|
+
//
|
|
208
|
+
// This MUST run as a plain (non-module) script BEFORE the `type="module"`
|
|
209
|
+
// script's imports execute: `log.js` binds its own reference to
|
|
210
|
+
// `console.log` the moment it's imported, so overriding console.log any
|
|
211
|
+
// later (even earlier in the module script's own source) would miss it —
|
|
212
|
+
// ES module imports always run before the importing module's own
|
|
213
|
+
// top-level code, regardless of source order.
|
|
214
|
+
window.__execLog = [];
|
|
215
|
+
const __nativeConsoleLog = console.log.bind(console);
|
|
216
|
+
console.log = (...consoleArgs) => {
|
|
217
|
+
__nativeConsoleLog(...consoleArgs);
|
|
218
|
+
|
|
219
|
+
const loggedPrefixes = ['[ActionsHandlerService]', '[IABookActions]', '[Demo]'];
|
|
220
|
+
if (typeof consoleArgs[0] !== 'string' || !loggedPrefixes.some((prefix) => consoleArgs[0].startsWith(prefix))) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const time = new Date().toISOString().split('T')[1].replace('Z', '');
|
|
225
|
+
const text = `[${time}] ` + consoleArgs
|
|
226
|
+
.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg)))
|
|
227
|
+
.join(' ');
|
|
228
|
+
window.__execLog.push(text);
|
|
229
|
+
if (window.__renderExecLogEntry) window.__renderExecLogEntry(text);
|
|
230
|
+
};
|
|
231
|
+
</script>
|
|
232
|
+
|
|
99
233
|
<script type="module">
|
|
100
234
|
/* eslint-disable */
|
|
101
235
|
|
|
@@ -139,31 +273,32 @@
|
|
|
139
273
|
iaBookActions.returnUrl = '';
|
|
140
274
|
iaBookActions.localCache = localCache;
|
|
141
275
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
276
|
+
// Loan-duration presets for QA — pick a short one (15s/30s) to run through
|
|
277
|
+
// the full warn -> auto-return -> silent-reborrow lifecycle quickly, or a
|
|
278
|
+
// longer one (60min matches the real 1-hour production default) to check
|
|
279
|
+
// the timing math. `?timer=` accepts any key below (e.g. ?timer=15s).
|
|
280
|
+
const timerPresets = {
|
|
281
|
+
'15s': { loanTotalTime: 15, loanRenewAtLast: 13, pageChangedInLast: 5 },
|
|
282
|
+
'30s': { loanTotalTime: 30, loanRenewAtLast: 27, pageChangedInLast: 10 },
|
|
283
|
+
'2': { loanTotalTime: 120, loanRenewAtLast: 110, pageChangedInLast: 30 },
|
|
284
|
+
'5': { loanTotalTime: 300, loanRenewAtLast: 240, pageChangedInLast: 60 },
|
|
285
|
+
'10': { loanTotalTime: 600, loanRenewAtLast: 480, pageChangedInLast: 120 },
|
|
286
|
+
'30': { loanTotalTime: 1800, loanRenewAtLast: 1500, pageChangedInLast: 600 },
|
|
287
|
+
'60': { loanTotalTime: 3600, loanRenewAtLast: 660, pageChangedInLast: 900 }, // production default
|
|
288
|
+
};
|
|
147
289
|
|
|
148
|
-
iaBookActions.loanRenewTimeConfig = loanTotalTime2Min;
|
|
149
290
|
let params = new URLSearchParams(document.location.search);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
iaBookActions.loanRenewTimeConfig = loanTotalTime1Hour;
|
|
162
|
-
break;
|
|
163
|
-
default:
|
|
164
|
-
iaBookActions.loanRenewTimeConfig = loanTotalTime2Min;
|
|
165
|
-
break;
|
|
166
|
-
}
|
|
291
|
+
const activeTimerKey = timerPresets[params.get('timer')] ? params.get('timer') : '2';
|
|
292
|
+
iaBookActions.loanRenewTimeConfig = timerPresets[activeTimerKey];
|
|
293
|
+
|
|
294
|
+
document.querySelectorAll('.timer-presets button').forEach((button) => {
|
|
295
|
+
if (button.dataset.timer === activeTimerKey) button.classList.add('active-preset');
|
|
296
|
+
button.addEventListener('click', () => {
|
|
297
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
298
|
+
searchParams.set('timer', button.dataset.timer);
|
|
299
|
+
window.location.search = searchParams.toString();
|
|
300
|
+
});
|
|
301
|
+
});
|
|
167
302
|
|
|
168
303
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
169
304
|
let secondsLeftOnLoan = iaBookActions.loanRenewTimeConfig.loanTotalTime;
|
|
@@ -202,6 +337,8 @@
|
|
|
202
337
|
item.checked = true;
|
|
203
338
|
}
|
|
204
339
|
item.addEventListener('click', (e) => {
|
|
340
|
+
console.log(`[Demo] error-response mode ${e.target.checked ? 'enabled' : 'disabled'}`);
|
|
341
|
+
|
|
205
342
|
var searchParams = new URLSearchParams(window.location.search);
|
|
206
343
|
var separate = '';
|
|
207
344
|
if (e.target.checked) {
|
|
@@ -251,6 +388,8 @@
|
|
|
251
388
|
|
|
252
389
|
document.querySelectorAll('.availableToBrowse input[type=radio]').forEach((item) => {
|
|
253
390
|
item.addEventListener('click', async (e) => {
|
|
391
|
+
console.log(`[Demo] "${e.target.value}" selected under availableToBrowse`);
|
|
392
|
+
|
|
254
393
|
if (e.target.value === 'user_has_browsed') {
|
|
255
394
|
lendingStatus1.user_has_browsed = true;
|
|
256
395
|
lendingStatus1.available_to_browse = false;
|
|
@@ -289,7 +428,11 @@
|
|
|
289
428
|
});
|
|
290
429
|
});
|
|
291
430
|
|
|
431
|
+
// WEBDEV-8322 scenario 1: informational-only warning modal.
|
|
432
|
+
// "Okay" (or closing it) must NOT renew the loan — only interacting
|
|
433
|
+
// with the book (scenario 3 below) does that.
|
|
292
434
|
document.querySelector('#show_warning_modal').addEventListener('click', async () => {
|
|
435
|
+
console.log('[Demo] scenario 1 button clicked: show warning modal');
|
|
293
436
|
if (!iaBookActions.lendingStatus.user_has_browsed) {
|
|
294
437
|
const newLendingStatus = { ...iaBookActions.lendingStatus, user_has_browsed: true };
|
|
295
438
|
iaBookActions.lendingStatus = newLendingStatus;
|
|
@@ -297,24 +440,28 @@
|
|
|
297
440
|
}
|
|
298
441
|
|
|
299
442
|
iaBookActions.showWarningModal();
|
|
300
|
-
|
|
301
|
-
if (iaBookActions.lendingStatus.user_has_browsed) {
|
|
302
|
-
iaBookActions.showWarningModal();
|
|
303
|
-
}
|
|
304
443
|
});
|
|
305
444
|
|
|
445
|
+
// WEBDEV-8322 scenario 2: loan auto-returned due to inactivity.
|
|
446
|
+
// No modal should appear and the page should NOT refresh — the reader
|
|
447
|
+
// just silently sits on whatever page it was on.
|
|
306
448
|
document.querySelector('#show_expired_modal').addEventListener('click', async () => {
|
|
449
|
+
console.log('[Demo] scenario 2 button clicked: force auto-return');
|
|
307
450
|
if (!iaBookActions.lendingStatus.user_has_browsed) {
|
|
308
451
|
const newLendingStatus = { ...iaBookActions.lendingStatus, user_has_browsed: true };
|
|
309
452
|
iaBookActions.lendingStatus = newLendingStatus;
|
|
310
453
|
await iaBookActions.updateComplete;
|
|
311
454
|
}
|
|
312
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
455
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
313
456
|
|
|
314
457
|
iaBookActions.browseHasExpired();
|
|
315
458
|
});
|
|
316
459
|
|
|
460
|
+
// WEBDEV-8322 scenario 4: patron returns to the tab after time away.
|
|
461
|
+
// If the loan already expired while hidden, this silently attempts to
|
|
462
|
+
// re-borrow (same success/failure paths as scenario 3).
|
|
317
463
|
document.querySelector('#resync_timer').addEventListener('click', async (e) => {
|
|
464
|
+
console.log('[Demo] scenario 4 button clicked: simulate visibilitychange (tab return)');
|
|
318
465
|
if (iaBookActions.lendingStatus.user_has_browsed) {
|
|
319
466
|
document.querySelector('ia-book-actions').dispatchEvent(
|
|
320
467
|
new Event('visibilitychange', {
|
|
@@ -324,7 +471,7 @@
|
|
|
324
471
|
})
|
|
325
472
|
);
|
|
326
473
|
}
|
|
327
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
474
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
328
475
|
});
|
|
329
476
|
|
|
330
477
|
document.querySelectorAll('.availableToBorrow input[type=radio]').forEach((item) => {
|
|
@@ -373,101 +520,233 @@
|
|
|
373
520
|
})
|
|
374
521
|
});
|
|
375
522
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
523
|
+
// WEBDEV-8322 scenario 3: patron interacts with the book (turns a page,
|
|
524
|
+
// etc). If the loan already expired (run scenario 2 first), this
|
|
525
|
+
// silently retries the loan — enable the error checkbox above beforehand
|
|
526
|
+
// to simulate someone else having already borrowed the book, which
|
|
527
|
+
// should surface the "Due to inactivity..." modal instead.
|
|
528
|
+
document.querySelectorAll('.pageChangedEvent').forEach((button) => {
|
|
529
|
+
button.addEventListener('click', () => {
|
|
530
|
+
console.log('[Demo] page-change / BookReader:userAction dispatched');
|
|
531
|
+
document.querySelector('ia-book-actions').dispatchEvent(
|
|
532
|
+
new CustomEvent('BookReader:userAction', {
|
|
533
|
+
detail: {},
|
|
534
|
+
bubbles: true,
|
|
535
|
+
composed: true,
|
|
536
|
+
})
|
|
537
|
+
);
|
|
538
|
+
});
|
|
539
|
+
});
|
|
386
540
|
|
|
387
541
|
// listen for IABookReader:BrowsingHasExpired
|
|
388
542
|
window.addEventListener('IABookReader:BrowsingHasExpired', () => {
|
|
389
543
|
console.log('IABookReader:BrowsingHasExpired EVENT FIRED');
|
|
390
544
|
});
|
|
545
|
+
|
|
546
|
+
// WEBDEV-8322 live status panel — the action bar alone doesn't always
|
|
547
|
+
// visibly change (e.g. right after auto-return), so mirror what the
|
|
548
|
+
// library's own log() calls already say is happening (create_token,
|
|
549
|
+
// renew_loan, browse_book, return_loan, and their success/error — see
|
|
550
|
+
// ActionsHandlerService) into an on-page log QA can read without
|
|
551
|
+
// opening devtools. The console.log interception itself lives in the
|
|
552
|
+
// plain <script> above this module script — see the comment there for
|
|
553
|
+
// why it can't live here.
|
|
554
|
+
const execLogEl = document.querySelector('#exec-log');
|
|
555
|
+
const loanStatusBadgeEl = document.querySelector('#loan-status-badge');
|
|
556
|
+
const liveStatusDetailEl = document.querySelector('#live-status-detail');
|
|
557
|
+
|
|
558
|
+
function renderExecLogEntry(text) {
|
|
559
|
+
const line = document.createElement('div');
|
|
560
|
+
line.textContent = text;
|
|
561
|
+
execLogEl.appendChild(line);
|
|
562
|
+
execLogEl.scrollTop = execLogEl.scrollHeight;
|
|
563
|
+
}
|
|
564
|
+
window.__renderExecLogEntry = renderExecLogEntry;
|
|
565
|
+
// flush anything logged before this module script finished loading
|
|
566
|
+
window.__execLog.forEach(renderExecLogEntry);
|
|
567
|
+
|
|
568
|
+
document.querySelector('#clear-exec-log').addEventListener('click', () => {
|
|
569
|
+
execLogEl.textContent = '';
|
|
570
|
+
window.__execLog = [];
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// The loan-status badge answers one question only: is the loan ACTIVE
|
|
574
|
+
// or has it been RETURNED? `browsingExpired` is the exact flag the
|
|
575
|
+
// library flips the instant auto-return executes (browseHasExpired()),
|
|
576
|
+
// so the badge changes in the same tick — even though the action bar
|
|
577
|
+
// itself doesn't show a modal or refresh at that moment.
|
|
578
|
+
function computeLoanStatus() {
|
|
579
|
+
const lendingStatus = iaBookActions.lendingStatus || {};
|
|
580
|
+
|
|
581
|
+
if (lendingStatus.browsingExpired) {
|
|
582
|
+
return { badge: 'RETURNED', className: 'status-returned' };
|
|
583
|
+
}
|
|
584
|
+
if (lendingStatus.user_has_browsed) {
|
|
585
|
+
return { badge: 'ACTIVE', className: 'status-active' };
|
|
586
|
+
}
|
|
587
|
+
return { badge: 'NO LOAN', className: 'status-none' };
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function computeLiveStatusDetail() {
|
|
591
|
+
const lendingStatus = iaBookActions.lendingStatus || {};
|
|
592
|
+
|
|
593
|
+
if (iaBookActions.loanRenewInProgress) {
|
|
594
|
+
return '🔄 Attempting silent re-borrow (create_token → renew_loan)…';
|
|
595
|
+
}
|
|
596
|
+
if (iaBookActions.warningModalOpen) {
|
|
597
|
+
return '⚠️ Warning modal open — closing it will NOT renew the loan';
|
|
598
|
+
}
|
|
599
|
+
if (lendingStatus.browsingExpired) {
|
|
600
|
+
return 'Auto-returned due to inactivity. By design: no modal, no refresh — only this badge and the action bar (Borrow) reflect it, until the patron interacts again.';
|
|
601
|
+
}
|
|
602
|
+
if (lendingStatus.user_has_browsed) {
|
|
603
|
+
const secondsLeft = Math.round(Number(lendingStatus.secondsLeftOnLoan || 0));
|
|
604
|
+
return `~${secondsLeft}s left on this loan`;
|
|
605
|
+
}
|
|
606
|
+
return 'Not currently browsing this book';
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
setInterval(() => {
|
|
610
|
+
const { badge, className } = computeLoanStatus();
|
|
611
|
+
loanStatusBadgeEl.textContent = badge;
|
|
612
|
+
loanStatusBadgeEl.className = `loan-status-badge ${className}`;
|
|
613
|
+
liveStatusDetailEl.textContent = computeLiveStatusDetail();
|
|
614
|
+
}, 250);
|
|
391
615
|
</script>
|
|
392
616
|
|
|
393
617
|
<div>
|
|
394
|
-
<
|
|
395
|
-
<
|
|
396
|
-
<
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
</
|
|
417
|
-
<
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
<
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
<
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
</
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
618
|
+
<div id="loan-status-row">
|
|
619
|
+
<fieldset>
|
|
620
|
+
<legend>WEBDEV-8322: loan duration for testing (reloads page)</legend>
|
|
621
|
+
<div class="timer-presets">
|
|
622
|
+
<button data-timer="15s">15 sec</button>
|
|
623
|
+
<button data-timer="30s">30 sec</button>
|
|
624
|
+
<button data-timer="2">2 min (default)</button>
|
|
625
|
+
<button data-timer="5">5 min</button>
|
|
626
|
+
<button data-timer="10">10 min</button>
|
|
627
|
+
<button data-timer="30">30 min</button>
|
|
628
|
+
<button data-timer="60">60 min (production default)</button>
|
|
629
|
+
</div>
|
|
630
|
+
<p style="color: #666; font-size: 11px; margin: 4px 0 0;">
|
|
631
|
+
Pick 15s/30s to watch the whole warn → auto-return → silent-reborrow
|
|
632
|
+
lifecycle play out on its own in under a minute, without clicking the scenario
|
|
633
|
+
buttons below.
|
|
634
|
+
</p>
|
|
635
|
+
</fieldset>
|
|
636
|
+
|
|
637
|
+
<fieldset>
|
|
638
|
+
<legend>WEBDEV-8322: live loan status (the action bar alone won't always make this obvious)</legend>
|
|
639
|
+
<div id="live-status-wrapper">
|
|
640
|
+
<span id="loan-status-badge" class="loan-status-badge status-none">NO LOAN</span>
|
|
641
|
+
<div id="live-status-detail">Not currently browsing this book</div>
|
|
642
|
+
</div>
|
|
643
|
+
<div id="exec-log"></div>
|
|
644
|
+
<p style="color: #666; font-size: 11px; margin: 4px 0 0; text-align: left;">
|
|
645
|
+
The badge flips to RETURNED the instant auto-return fires (scenario 2) — even though
|
|
646
|
+
no modal appears and the page doesn't refresh, per the ticket. The log below mirrors
|
|
647
|
+
every create_token / browse_book / renew_loan / return_loan call and its success/error
|
|
648
|
+
result as it happens.
|
|
649
|
+
</p>
|
|
650
|
+
<button id="clear-exec-log" style="margin-top: 6px; padding: 4px 8px; cursor: pointer;">Clear log</button>
|
|
651
|
+
</fieldset>
|
|
652
|
+
</div>
|
|
653
|
+
<div id="auto-renew-controls">
|
|
654
|
+
<fieldset style="margin-top: 10px;">
|
|
655
|
+
<legend style="color: black;">WEBDEV-8322: loan auto-renew QA scenarios (requires `user_has_browsed`)</legend>
|
|
656
|
+
<table aria-hidden="true">
|
|
657
|
+
<tbody><tr>
|
|
658
|
+
<td class="action-button">
|
|
659
|
+
<button id="show_warning_modal">1. Show "Are you still there?" modal<br>(Okay does NOT renew the loan)</button>
|
|
660
|
+
</td>
|
|
661
|
+
<td class="action-button">
|
|
662
|
+
<button id="show_expired_modal">2. Auto-return due to inactivity<br>(no modal, page stays put)</button>
|
|
663
|
+
</td>
|
|
664
|
+
<td class="action-button">
|
|
665
|
+
<button class="pageChangedEvent">3. Interact with book (turn page)<br>silently renew if interact in given time</button>
|
|
666
|
+
</td>
|
|
667
|
+
<td class="action-button">
|
|
668
|
+
<button id="resync_timer">4. Return to tab after time away<br>(visibilitychange — silent retry if expired)</button>
|
|
669
|
+
</td>
|
|
670
|
+
</tr>
|
|
671
|
+
</tbody></table>
|
|
672
|
+
<p style="color: #666; font-size: 11px; margin: 8px 0 0;">
|
|
673
|
+
Try 2 → 3 (or 2 → 4) in sequence to walk through the full "auto-returned, then patron
|
|
674
|
+
keeps reading" flow the ticket describes.
|
|
675
|
+
</p>
|
|
676
|
+
</fieldset>
|
|
677
|
+
</div>
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
<div id="lending-bar-controls">
|
|
681
|
+
<fieldset>
|
|
682
|
+
<legend>Dev testing for book title bar</legend>
|
|
683
|
+
<table class="initial">
|
|
684
|
+
<tr>
|
|
685
|
+
<td class="titleBar">
|
|
686
|
+
<label><input type="checkbox" name="title" value="title" />Title Bar</label>
|
|
687
|
+
</td>
|
|
688
|
+
<td class="searchParam">
|
|
689
|
+
<label><input type="checkbox" name="search" value="Search Param" />Search Param</label>
|
|
690
|
+
</td>
|
|
691
|
+
<td>
|
|
692
|
+
<label class="ia-button"><button class="pageChangedEvent">Page Change Event</button></label>
|
|
693
|
+
</td>
|
|
694
|
+
</tr>
|
|
695
|
+
</table>
|
|
696
|
+
</fieldset>
|
|
697
|
+
|
|
698
|
+
<fieldset>
|
|
699
|
+
<legend>Dev testing for book action bar</legend>
|
|
700
|
+
<table class="initial">
|
|
701
|
+
<tr colspan='5'>
|
|
702
|
+
<td class="errorEnable">
|
|
703
|
+
<label><input type="checkbox" name="errorEnable" value="errorEnable" />Do you want to see error response?</label>
|
|
704
|
+
<span style="color: #666; font-size: 11px; display: block; padding: 0 10px 10px;">
|
|
705
|
+
Tip: turn this on before scenarios 3/4 below to simulate someone else having
|
|
706
|
+
already borrowed the book (shows the "Due to inactivity..." modal).
|
|
707
|
+
</span>
|
|
708
|
+
</td>
|
|
709
|
+
</tr>
|
|
710
|
+
<tr>
|
|
711
|
+
<td class="userState">
|
|
712
|
+
<label><input type="checkbox" name="user" value="isAdmin" />isAdmin</label>
|
|
713
|
+
<label><input type="checkbox" name="user" value="isLoggedIn" />isLoggedIn</label>
|
|
714
|
+
</td>
|
|
715
|
+
<td class="printDisabled">
|
|
716
|
+
<label><input type="checkbox" name="is_printdisabled" value="is_printdisabled" />is_printdisabled</label>
|
|
717
|
+
<label><input type="checkbox" name="user_is_printdisabled" value="user_is_printdisabled" />user_is_printdisabled</label>
|
|
718
|
+
</td>
|
|
719
|
+
<td class="availableToBrowse">
|
|
720
|
+
<label><input type="radio" name="browse" value="available_to_browse" />available_to_browse</label>
|
|
721
|
+
<label><input type="radio" name="browse" value="user_has_browsed" />user_has_browsed</label>
|
|
722
|
+
<label><input type="radio" name="browse" value="browsingExpired" />browsingExpired</label>
|
|
723
|
+
</td>
|
|
724
|
+
<td class="availableToBorrow">
|
|
725
|
+
<label><input type="radio" name="borrow" value="available_to_borrow" />available_to_borrow</label>
|
|
726
|
+
<label><input type="radio" name="borrow" value="user_on_waitlist" />user_on_waitlist</label>
|
|
727
|
+
<label><input type="radio" name="borrow" value="user_can_claim_waitlist" />user_can_claim_waitlist</label>
|
|
728
|
+
<label><input type="radio" name="borrow" value="available_to_waitlist" />available_to_waitlist</label>
|
|
729
|
+
<label><input type="radio" name="borrow" value="user_has_borrowed" />user_has_borrowed</label>
|
|
730
|
+
</td>
|
|
731
|
+
<td class="purchase">
|
|
732
|
+
<label><input type="checkbox" name="purchase" value="purchase" />purchase</label>
|
|
733
|
+
</td>
|
|
734
|
+
|
|
735
|
+
<td class="reflect">
|
|
736
|
+
<input type="button" style="padding: 10px;
|
|
737
|
+
background: #194880;
|
|
738
|
+
color: white;
|
|
739
|
+
font-weight: bold; display: none" name="purchase" value="Reflect" />
|
|
740
|
+
</td>
|
|
741
|
+
</tr>
|
|
742
|
+
<tr>
|
|
743
|
+
<td>
|
|
744
|
+
</td>
|
|
745
|
+
</tr>
|
|
746
|
+
</table>
|
|
747
|
+
</fieldset>
|
|
748
|
+
</div>
|
|
749
|
+
|
|
471
750
|
</div>
|
|
472
751
|
<modal-manager></modal-manager>
|
|
473
752
|
</body>
|
package/package.json
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
"description": "Bookreader actions for borrowable book",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
|
-
"url": "git+https://github.com/internetarchive/iaux-
|
|
6
|
+
"url": "git+https://github.com/internetarchive/iaux-book-actions.git"
|
|
7
7
|
},
|
|
8
8
|
"author": "Internet Archive",
|
|
9
9
|
"license": "AGPL-3.0-only",
|
|
10
|
-
"version": "1.4.3-
|
|
10
|
+
"version": "1.4.3-alpha1",
|
|
11
11
|
"main": "index.js",
|
|
12
12
|
"module": "index.js",
|
|
13
13
|
"publishConfig": {
|