@internetarchive/ia-book-actions 1.4.3 → 1.4.4-alpha10

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