@internetarchive/ia-book-actions 0.0.29-alpha11 → 0.0.29-alpha12

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/demo/index.html CHANGED
@@ -97,7 +97,7 @@
97
97
  import { LocalCache } from '@internetarchive/local-cache';
98
98
 
99
99
  const localCache = new LocalCache({
100
- namespace: '1HourLoanStorage',
100
+ namespace: 'loanRenew',
101
101
  defaultTTL: 1 * 60, // 1 minute
102
102
  });
103
103
 
@@ -128,14 +128,14 @@
128
128
  iaBookActions.tokenDelay = 2000; // 2 seconds
129
129
  iaBookActions.returnUrl = 'https://openlibrary.org';
130
130
  iaBookActions.localCache = localCache;
131
- iaBookActions.autoRenewConfig = {
131
+ iaBookActions.loanRenewConfig = {
132
132
  totalTime: 60, // 60 second = 1 min
133
133
  autoCheckAt: 55, // totalTime - 10th minute
134
- FlippedInLast: 15, // within last 15 second/minute
134
+ pageChangedInLast: 15, // within last 15 second/minute
135
135
  };
136
136
 
137
137
  let lendingStatus1 = iaBookActions.lendingStatus;
138
- let secondsLeftOnLoan = iaBookActions.autoRenewConfig.totalTime;
138
+ let secondsLeftOnLoan = iaBookActions.loanRenewConfig.totalTime;
139
139
 
140
140
  document.querySelectorAll('.titleBar input[type=checkbox]').forEach((item) => {
141
141
  item.addEventListener('click', (e) => {
@@ -212,10 +212,10 @@
212
212
  await localCache.set({
213
213
  key: `${identifier}-loanTime`,
214
214
  value: new Date(), // current time
215
- ttl: Number(iaBookActions.autoRenewConfig.totalTime),
216
- })
215
+ ttl: Number(iaBookActions.loanRenewConfig.totalTime),
216
+ });
217
217
 
218
- await localCache.delete(`${identifier}-pageFlipTime`);
218
+ await localCache.delete(`${identifier}-pageChangedTime`);
219
219
  } catch (error) {}
220
220
 
221
221
  } else if(e.target.value === 'browsingExpired') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.0.29-alpha11",
3
+ "version": "0.0.29-alpha12",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -12,7 +12,7 @@ import { purchaseIcon } from '../assets/data/purchase.js';
12
12
  import {
13
13
  analyticsCategories,
14
14
  analyticsActions,
15
- } from '../config/analytics-event-and-category.js';
15
+ } from '../core/config/analytics-event-and-category.js';
16
16
  import {
17
17
  dropdownOpened,
18
18
  dropdownClosed,
@@ -32,7 +32,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
32
32
  dropdownArrow: { type: String },
33
33
  disabled: { type: Boolean },
34
34
  returnUrl: { type: String },
35
- browseAgainNow: { type: Boolean },
35
+ renewNow: { type: Boolean },
36
36
  };
37
37
  }
38
38
 
@@ -52,7 +52,7 @@ export class CollapsibleActionGroup extends ActionsHandler {
52
52
  this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
53
53
  this.disabled = false;
54
54
  this.returnUrl = '';
55
- this.browseAgainNow = false;
55
+ this.renewNow = false;
56
56
  }
57
57
 
58
58
  updated(changed) {
@@ -63,20 +63,21 @@ export class CollapsibleActionGroup extends ActionsHandler {
63
63
  this.resetActions();
64
64
  }
65
65
 
66
- if (changed.has('browseAgainNow') && this.browseAgainNow === true) {
67
- this.dispatchAutoRenewBookEvent();
66
+ if (changed.has('renewNow') && this.renewNow === true) {
67
+ this.dispatchLoanRenewEvent();
68
68
  }
69
69
  }
70
70
 
71
71
  // dispatch this event to loan renew handler
72
- dispatchAutoRenewBookEvent() {
72
+ dispatchLoanRenewEvent() {
73
73
  const { category, action } = {
74
74
  category: analyticsCategories.browse,
75
- action: analyticsActions.browseAutoRenew,
75
+ action: analyticsActions.browseLoanRenew,
76
76
  };
77
77
 
78
+ // listen in action-handler.js to execute ajax call on petabox.
78
79
  this.dispatchEvent(
79
- new CustomEvent('autoRenewLoan', {
80
+ new CustomEvent('loanRenew', {
80
81
  detail: {
81
82
  event: { category, action },
82
83
  },
@@ -35,9 +35,9 @@ export default class TimerCountdown extends LitElement {
35
35
  // execute 50th minute check
36
36
  if (Math.round(this.time) === this.autoCheckAt) {
37
37
  this.dispatchEvent(
38
- new CustomEvent('autoRenewAttempt', {
38
+ new CustomEvent('IABookActions:loanRenew', {
39
39
  detail: {
40
- bookPageChange: false,
40
+ isPageChanged: false,
41
41
  },
42
42
  bubbles: true,
43
43
  composed: true,
@@ -5,27 +5,24 @@ export class ToastMessage extends LitElement {
5
5
  return {
6
6
  texts: { type: String },
7
7
  dismisOnClick: { type: Boolean },
8
- hideToast: { type: Boolean },
9
8
  clostAfter: { type: Number },
10
9
  };
11
10
  }
12
11
 
13
12
  constructor() {
14
13
  super();
15
- this.texts = '';
16
- this.textClass = '';
17
- this.hideToast = false;
14
+ this.texts = null;
18
15
  this.clostAfter = 0;
19
16
  }
20
17
 
21
18
  render() {
22
- return !this.hideToast
19
+ return this.texts
23
20
  ? html`
24
21
  <span
25
- class="toast-message fade-in ${this.textClass}"
22
+ class="toast-message fade-in"
26
23
  title="Click/tap to close"
27
24
  @click=${() => {
28
- this.dismisOnClick ? (this.hideToast = true) : nothing;
25
+ this.dismisOnClick ? this.texts = null : nothing;
29
26
  }}
30
27
  >${this.texts}</span
31
28
  >
@@ -40,6 +37,7 @@ export class ToastMessage extends LitElement {
40
37
  :host {
41
38
  display: inline-block;
42
39
  }
40
+
43
41
  .toast-message {
44
42
  z-index: 2;
45
43
  position: absolute;
@@ -13,7 +13,7 @@ export const analyticsCategories = {
13
13
  export const analyticsActions = {
14
14
  browse: 'Borrow-1Hour',
15
15
  browseAgain: 'Borrow-Again',
16
- browseAutoRenew: 'Borrow-Auto-Renew',
16
+ browseLoanRenew: 'Borrow-Loan-Renew',
17
17
  borrow: 'Borrow-14Days',
18
18
  waitlistJoin: 'JoinWaitlist',
19
19
  waitlistLeave: 'LeaveWaitlist',
@@ -43,8 +43,8 @@ export default class ActionsHandler extends LitElement {
43
43
  this.sendEvent(category, action);
44
44
  });
45
45
 
46
- this.addEventListener('autoRenewLoan', ({ detail }) => {
47
- this.handleAutoRenewLoan();
46
+ this.addEventListener('loanRenew', ({ detail }) => {
47
+ this.handleLoanRenew();
48
48
  const { category, action } = detail.event;
49
49
  this.sendEvent(category, action);
50
50
  });
@@ -117,7 +117,7 @@ export default class ActionsHandler extends LitElement {
117
117
  });
118
118
  }
119
119
 
120
- handleAutoRenewLoan() {
120
+ handleLoanRenew() {
121
121
  const action = 'renew_loan';
122
122
  this.setBrowseTimeSession();
123
123
 
@@ -289,11 +289,11 @@ export default class ActionsHandler extends LitElement {
289
289
  await this.localCache.set({
290
290
  key: `${this.identifier}-loanTime`,
291
291
  value: new Date(), // current time
292
- ttl: Number(this.autoRenewConfig.totalTime),
292
+ ttl: Number(this.loanRenewConfig.totalTime),
293
293
  });
294
294
 
295
295
  // delete flip time
296
- await this.localCache.delete(`${this.identifier}-pageFlipTime`);
296
+ await this.localCache.delete(`${this.identifier}-pageChangedTime`);
297
297
  } catch (error) {
298
298
  console.log(error);
299
299
  }
@@ -4,44 +4,43 @@ import { nothing } from 'lit';
4
4
  * This class is used to determine if use is eligible for auto renew loan.
5
5
  *
6
6
  */
7
- export class OneHourAutoRenew {
7
+ export class OneHourLoanRenew {
8
8
  constructor(
9
- isPageClick,
9
+ isPageChanged,
10
10
  identifier,
11
11
  localCache,
12
- autoRenewConfig
12
+ loanRenewConfig
13
13
  ) {
14
- this.isPageClick = isPageClick;
14
+ this.isPageChanged = isPageChanged;
15
15
  this.identifier = identifier;
16
16
  this.localCache = localCache;
17
- this.autoRenewConfig = autoRenewConfig;
17
+ this.loanRenewConfig = loanRenewConfig;
18
18
 
19
19
  // messages for auto return machenism
20
- this.autoRenewMessage = 'This book has been renewed for another hour.';
21
- this.autoReturnMessage =
20
+ this.loanRenewMessage = 'This book has been renewed for another hour.';
21
+ this.loanReturnMessage =
22
22
  'This book has been auto-returned due to inactivity.';
23
- this.autoReturnWarning =
23
+ this.loanReturnWarning =
24
24
  'This book will be auto-returned in 10 minutes unless you turn a page.';
25
25
 
26
26
  // private props
27
- this.autoRenewResult = {
28
- toastTexts: '',
29
- hideToast: true,
30
- browseAgainNow: false,
27
+ this.loanRenewResult = {
28
+ texts: null,
29
+ renewNow: false,
31
30
  };
32
31
 
33
- return this.handleBookAutoRenew();
32
+ return this.handleLoanRenew();
34
33
  }
35
34
 
36
- handleBookAutoRenew() {
35
+ handleLoanRenew() {
37
36
  try {
38
37
  // when user click/flip on book page
39
- if (this.isPageClick) {
40
- console.log('page flipped!!');
41
- return this.userFlippedBookPage(); // user clicked on page
38
+ if (this.isPageChanged) {
39
+ console.log('page changed!!');
40
+ return this.pageChanged(); // user clicked on page
42
41
  }
43
-
44
- return this.autoCheckerTimer(); // auto checker at 50th minute
42
+
43
+ return this.autoChecker(); // auto checker at 50th minute
45
44
  } catch (error) {
46
45
  console.log(error);
47
46
  }
@@ -49,20 +48,11 @@ export class OneHourAutoRenew {
49
48
  return nothing;
50
49
  }
51
50
 
52
- // set new pageFlipTime in indexedDB
53
- async setPageFlippedTime() {
54
- await this.localCache.set({
55
- key: `${this.identifier}-pageFlipTime`,
56
- value: new Date(), // current time
57
- ttl: Number(this.autoRenewConfig.totalTime),
58
- });
59
- }
60
-
61
- async userFlippedBookPage() {
51
+ async pageChanged() {
62
52
  const {
63
53
  totalTime, // 60
64
54
  autoCheckAt, // 50
65
- } = this.autoRenewConfig;
55
+ } = this.loanRenewConfig;
66
56
  const currentTime = new Date();
67
57
  const loanTime = await this.localCache.get(`${this.identifier}-loanTime`);
68
58
 
@@ -70,33 +60,32 @@ export class OneHourAutoRenew {
70
60
  loanTime,
71
61
  totalTime - autoCheckAt,
72
62
  'add'
73
- ); // 50 seconds
63
+ );
74
64
 
75
65
  // if user viewed new page in last 10 minutes, renew immediately
76
66
  if (currentTime >= lastTimeFrame) {
77
- console.log('1 YES NOW BORROW IT AGAIN NOW!');
78
- this.autoRenewResult.toastTexts = this.autoRenewMessage;
79
- this.autoRenewResult.hideToast = false;
80
- this.autoRenewResult.browseAgainNow = true;
67
+ console.log('Yes, borrow it again now!');
68
+ this.loanRenewResult.texts = this.loanRenewMessage;
69
+ this.loanRenewResult.renewNow = true;
81
70
 
82
- this.setNewBrowseTime();
71
+ this.setLoanRenewedTime();
83
72
  }
84
73
 
85
- this.setPageFlippedTime();
86
- return this.autoRenewResult;
74
+ this.setPageChangedTime();
75
+ return this.loanRenewResult;
87
76
  }
88
77
 
89
- async autoCheckerTimer() {
78
+ async autoChecker() {
90
79
  const currentTime = new Date();
91
- const { FlippedInLast } = this.autoRenewConfig;
80
+ const { pageChangedInLast } = this.loanRenewConfig;
92
81
  const lastPageFlipTime = await this.localCache.get(
93
- `${this.identifier}-pageFlipTime`
82
+ `${this.identifier}-pageChangedTime`
94
83
  );
95
84
 
96
85
  // last 15 min if used flipped a page.
97
86
  const lastFlipTimeFrame = this.changeTime(
98
87
  currentTime,
99
- FlippedInLast,
88
+ pageChangedInLast,
100
89
  'sub'
101
90
  ); // 15 seconds
102
91
 
@@ -105,29 +94,37 @@ export class OneHourAutoRenew {
105
94
  lastPageFlipTime <= lastFlipTimeFrame
106
95
  ) {
107
96
  // not viewed
108
- console.log('Not viewed, warning message!');
109
- this.autoRenewResult.toastTexts = this.autoReturnWarning;
110
- this.autoRenewResult.browseAgainNow = false;
111
- this.autoRenewResult.hideToast = false;
97
+ console.log('Not viewed, don\'t borrow it!');
98
+ this.loanRenewResult.texts = this.loanReturnWarning;
99
+ this.loanRenewResult.renewNow = false;
112
100
  } else if (lastPageFlipTime >= lastFlipTimeFrame) {
113
101
  // viewed in last time frame
114
- console.log('Viewed, auto renew and message!');
115
- this.autoRenewResult.toastTexts = this.autoRenewMessage;
116
- this.autoRenewResult.browseAgainNow = true;
117
- this.autoRenewResult.hideToast = false;
102
+ console.log('Yes viewed, borrow it again!');
103
+ this.loanRenewResult.texts = this.loanRenewMessage;
104
+ this.loanRenewResult.renewNow = true;
118
105
 
119
- this.setNewBrowseTime();
106
+ this.setLoanRenewedTime();
120
107
  }
121
108
 
122
- return this.autoRenewResult;
109
+ return this.loanRenewResult;
110
+ }
111
+
112
+
113
+ // save page changed time in indexedDB
114
+ async setPageChangedTime() {
115
+ await this.localCache.set({
116
+ key: `${this.identifier}-pageChangedTime`,
117
+ value: new Date(), // current time
118
+ ttl: Number(this.loanRenewConfig.totalTime),
119
+ });
123
120
  }
124
121
 
125
- async setNewBrowseTime() {
122
+ async setLoanRenewedTime() {
126
123
  try {
127
124
  // last 15 min if used flipped a page.
128
125
  const expireDate = this.changeTime(
129
126
  new Date(),
130
- this.autoRenewConfig.totalTime,
127
+ this.loanRenewConfig.totalTime,
131
128
  'add'
132
129
  ); // 15 seconds
133
130
 
@@ -135,11 +132,11 @@ export class OneHourAutoRenew {
135
132
  await this.localCache.set({
136
133
  key: `${this.identifier}-loanTime`,
137
134
  value: expireDate, // expireDate time
138
- ttl: Number(this.autoRenewConfig.totalTime),
135
+ ttl: Number(this.loanRenewConfig.totalTime),
139
136
  });
140
137
 
141
- // delete pageFlipTime when book is auto renew at nth minute
142
- await this.localCache.delete(`${this.identifier}-pageFlipTime`);
138
+ // delete pageChangedTime when book is auto renew at nth minute
139
+ await this.localCache.delete(`${this.identifier}-pageChangedTime`);
143
140
  } catch (error) {
144
141
  console.log(error);
145
142
  }
@@ -15,7 +15,7 @@ import './components/toast-message.js';
15
15
  import { mobileContainerWidth } from './core/config/constants.js';
16
16
  import { GetLendingActions } from './core/services/get-lending-actions.js';
17
17
  import { LoanTokenPoller } from './core/services/loan-token-poller.js';
18
- import { OneHourAutoRenew } from './core/services/one-hour-auto-renew.js';
18
+ import { OneHourLoanRenew } from './core/services/one-hour-loan-renew.js';
19
19
 
20
20
  export const events = {
21
21
  browseExpired: 'IABookReader:BrowsingHasExpired',
@@ -41,8 +41,8 @@ export default class IABookActions extends LitElement {
41
41
  modal: { Object },
42
42
  tokenDelay: { type: Number },
43
43
  localCache: { type: Object },
44
- autoRenewConfig: { type: Object },
45
- autoRenewResult: { type: Object },
44
+ loanRenewConfig: { type: Object },
45
+ loanRenewResult: { type: Object },
46
46
  };
47
47
  }
48
48
 
@@ -62,17 +62,18 @@ export default class IABookActions extends LitElement {
62
62
  this.modal = undefined;
63
63
  this.tokenDelay = 120000; // 2 minutes
64
64
  this.localCache = new LocalCache({
65
- namespace: '1HourLoanStorage',
65
+ namespace: 'loanRenew',
66
66
  });
67
67
 
68
68
  // loan auto renew
69
- this.autoRenewConfig = {};
70
- this.autoRenewResult = {
71
- toastTexts: '',
72
- hideToast: true,
73
- browseAgainNow: false,
69
+ this.isPageChanged = false;
70
+ this.loanRenewConfig = {};
71
+ this.loanRenewResult = {
72
+ texts: null,
73
+ renewNow: false,
74
74
  };
75
75
 
76
+
76
77
  // private props
77
78
  this.primaryActions = [];
78
79
  this.primaryTitle = '';
@@ -83,7 +84,7 @@ export default class IABookActions extends LitElement {
83
84
  this.consecutiveLoanCounts = 1; // consecutive loan count
84
85
  this.browserTimer = undefined;
85
86
 
86
- this.bindAutoRenewEvent();
87
+ this.bindLoanRenewEvents();
87
88
  }
88
89
 
89
90
  disconnectedCallback() {
@@ -111,49 +112,53 @@ export default class IABookActions extends LitElement {
111
112
  }
112
113
  }
113
114
 
114
- bindAutoRenewEvent() {
115
- // dispatched this event from timer-countdown
116
- this.addEventListener('BookReader:pageChanged', event => {
117
- console.log('here: ', event)
118
- })
115
+ bindLoanRenewEvents() {
116
+ // dispatched this event from bookreader page changed
117
+ this.addEventListener('BookReader:pageChanged', e => {
119
118
 
120
- this.addEventListener('autoRenewAttempt', async event => {
121
- const isPageClick = event.detail.bookPageChange;
119
+ // early return if book is not browsed (1 hour borrow)
120
+ if (this.borrowType !== 'browsed') return nothing;
122
121
 
123
- // early return if user is not browsed book
124
- if (isPageClick && this.borrowType !== 'browsed') return nothing;
122
+ this.isPageChanged = true;
123
+ this.executeLoanRenew();
124
+ })
125
125
 
126
- this.autoRenewResult = await new OneHourAutoRenew(
127
- isPageClick,
128
- this.identifier,
129
- this.localCache,
130
- this.autoRenewConfig
131
- );
126
+ // dispatched this event from timer-countdown
127
+ this.addEventListener('IABookActions:loanRenew', e => {
128
+ this.isPageChanged = false;
129
+ this.executeLoanRenew();
130
+ });
131
+ }
132
132
 
133
- this.toastTexts = this.autoRenewResult.toastTexts;
134
- this.hideToast = this.autoRenewResult.hideToast;
135
- this.browseAgainNow = this.autoRenewResult.browseAgainNow;
133
+ async executeLoanRenew() {
134
+ this.loanRenewResult = await new OneHourLoanRenew(
135
+ this.isPageChanged,
136
+ this.identifier,
137
+ this.localCache,
138
+ this.loanRenewConfig
139
+ );
136
140
 
137
- if (this.autoRenewResult.browseAgainNow) {
138
- this.tokenPoller.disconnectedInterval();
139
- await this.browseHasRenew();
140
- }
141
+ console.log(this.loanRenewResult)
141
142
 
142
- return nothing;
143
- });
143
+ if (this.loanRenewResult.renewNow) {
144
+ this.tokenPoller.disconnectedInterval();
145
+ await this.browseHasRenew();
146
+ }
147
+
148
+ return nothing;
144
149
  }
145
150
 
146
151
  async browseHasExpired() {
147
152
  const currStatus = { ...this.lendingStatus, browsingExpired: true };
148
153
  this.lendingStatus = currStatus;
149
- this.autoRenewResult.browseAgainNow = false;
154
+ this.loanRenewResult.renewNow = false;
150
155
 
151
156
  // remove respected key:value
152
157
  await this.localCache.delete(`${this.identifier}-loanTime`);
153
- await this.localCache.delete(`${this.identifier}-pageFlipTime`);
158
+ await this.localCache.delete(`${this.identifier}-pageChangedTime`);
154
159
 
155
160
  // show message after browsed book is expired.
156
- this.autoRenewResult.toastTexts = 'This book has been auto-returned due to inactivity.';
161
+ this.loanRenewResult.texts = 'This book has been auto-returned due to inactivity.';
157
162
  }
158
163
 
159
164
  async browseHasRenew() {
@@ -282,7 +287,7 @@ export default class IABookActions extends LitElement {
282
287
  // - start token poller immediately
283
288
  setTimeout(() => {
284
289
  this.startLoanTokenPoller();
285
- }, this.autoRenewResult.browseAgainNow ? this.tokenDelay : 100);
290
+ }, this.loanRenewResult.renewNow ? this.tokenDelay : 100);
286
291
  }
287
292
 
288
293
  render() {
@@ -308,7 +313,7 @@ export default class IABookActions extends LitElement {
308
313
  return this.borrowType === 'browsed'
309
314
  ? html`<timer-countdown
310
315
  time=${Number(this.lendingStatus.secondsLeftOnLoan)}
311
- .autoCheckAt=${this.autoRenewConfig.autoCheckAt}
316
+ .autoCheckAt=${this.loanRenewConfig.autoCheckAt}
312
317
  ></timer-countdown>`
313
318
  : nothing;
314
319
  }
@@ -316,16 +321,15 @@ export default class IABookActions extends LitElement {
316
321
  get toastMessageTemplate() {
317
322
  return html`
318
323
  <toast-message
319
- .texts=${this.autoRenewResult.toastTexts}
324
+ .texts=${this.loanRenewResult.texts}
320
325
  ?dismisOnClick=${Boolean(true)}
321
- ?hideToast=${this.autoRenewResult.hideToast}
322
326
  ></toast-message>
323
327
  `;
324
328
  }
325
329
 
326
330
  get bookActionBar() {
327
331
  return html`
328
- <button @click=${() => this.pageFlipEvent()}>Page Flip</button>
332
+ <button @click=${() => this.pageChangedEvent()}>Page Change</button>
329
333
  <collapsible-action-group
330
334
  .userid=${this.userid}
331
335
  .identifier=${this.identifier}
@@ -336,10 +340,10 @@ export default class IABookActions extends LitElement {
336
340
  .borrowType=${this.borrowType}
337
341
  .returnUrl=${this.returnUrl}
338
342
  .localCache=${this.localCache}
339
- .autoRenewConfig=${this.autoRenewConfig}
343
+ .loanRenewConfig=${this.loanRenewConfig}
340
344
  ?hasAdminAccess=${this.hasAdminAccess}
341
345
  ?disabled=${this.disableActionGroup}
342
- ?browseAgainNow=${this.autoRenewResult.browseAgainNow}
346
+ ?renewNow=${this.loanRenewResult.renewNow}
343
347
  @lendingActionError=${this.handleLendingActionError}
344
348
  @toggleActionGroup=${this.handleToggleActionGroup}
345
349
  >
@@ -350,11 +354,11 @@ export default class IABookActions extends LitElement {
350
354
  }
351
355
 
352
356
  // will move this function to bookreader...
353
- pageFlipEvent() {
357
+ pageChangedEvent() {
354
358
  // dispatch event to say book page has flipped
355
359
  document.querySelector('ia-book-actions').dispatchEvent(
356
- new CustomEvent('autoRenewAttempt', {
357
- detail: { bookPageChange: true },
360
+ new CustomEvent('BookReader:pageChanged', {
361
+ detail: { isPageChanged: true },
358
362
  bubbles: true,
359
363
  composed: true,
360
364
  })