@internetarchive/ia-book-actions 0.1.4 → 0.1.5-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/demo/index.html +3 -3
- package/package.json +1 -1
- package/src/components/collapsible-action-group.js +25 -11
- package/src/components/timer-countdown.js +82 -26
- package/src/core/config/analytics-event-and-category.js +2 -1
- package/src/core/services/actions-handler/actions-handler.js +122 -33
- package/src/core/services/doc-cookies.js +23 -1
- package/src/core/services/loan-token-poller.js +1 -1
- package/src/ia-book-actions.js +30 -24
- package/demo/with-bookreader.html +0 -146
package/demo/index.html
CHANGED
|
@@ -131,11 +131,11 @@
|
|
|
131
131
|
iaBookActions.returnUrl = 'https://openlibrary.org';
|
|
132
132
|
iaBookActions.localCache = localCache;
|
|
133
133
|
|
|
134
|
-
let loanTotalTime2Min = { loanTotalTime:
|
|
135
|
-
let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast:
|
|
134
|
+
let loanTotalTime2Min = { loanTotalTime: 10, loanRenewAtLast: 5, pageChangedInLast: 5 };
|
|
135
|
+
let loanTotalTime5Min = { loanTotalTime: 300, loanRenewAtLast: 290, pageChangedInLast: 15 };
|
|
136
136
|
let loanTotalTime1Hour = { loanTotalTime: 3600, loanRenewAtLast: 600, pageChangedInLast: 900 };
|
|
137
137
|
|
|
138
|
-
iaBookActions.loanRenewTimeConfig =
|
|
138
|
+
iaBookActions.loanRenewTimeConfig = loanTotalTime2Min;
|
|
139
139
|
|
|
140
140
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
141
141
|
let secondsLeftOnLoan = iaBookActions.loanRenewTimeConfig.loanTotalTime;
|
package/package.json
CHANGED
|
@@ -32,7 +32,8 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
32
32
|
dropdownArrow: { type: String },
|
|
33
33
|
disabled: { type: Boolean },
|
|
34
34
|
returnUrl: { type: String },
|
|
35
|
-
|
|
35
|
+
autoRenew: { type: Boolean },
|
|
36
|
+
autoReturn: { type: Boolean },
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -52,7 +53,8 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
52
53
|
this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
|
|
53
54
|
this.disabled = false;
|
|
54
55
|
this.returnUrl = '';
|
|
55
|
-
this.
|
|
56
|
+
this.autoRenew = false;
|
|
57
|
+
this.autoReturn = false;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
updated(changed) {
|
|
@@ -63,21 +65,33 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
63
65
|
this.resetActions();
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
if (changed.has('
|
|
67
|
-
this.
|
|
68
|
+
if (changed.has('autoRenew') && this.autoRenew === true) {
|
|
69
|
+
this.dispatchLoanEvent('autoRenew');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (changed.has('autoReturn') && this.autoReturn === true) {
|
|
73
|
+
this.dispatchLoanEvent('autoReturn');
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
/**
|
|
78
|
+
* dispatch event when book is auto renewed / returned
|
|
79
|
+
* listen these events in action-handler.js
|
|
80
|
+
* @see ActionsHandler
|
|
81
|
+
*
|
|
82
|
+
* @param {string} event - autoRenew|autoReturn
|
|
83
|
+
* @memberof CollapsibleActionGroup
|
|
84
|
+
*/
|
|
85
|
+
dispatchLoanEvent(event) {
|
|
86
|
+
const category = analyticsCategories.browse;
|
|
87
|
+
const action =
|
|
88
|
+
event === 'autoRenew'
|
|
89
|
+
? analyticsActions.browseAutoRenew
|
|
90
|
+
: analyticsActions.browseAutoReturn;
|
|
77
91
|
|
|
78
92
|
// listen in action-handler.js to execute ajax call on petabox.
|
|
79
93
|
this.dispatchEvent(
|
|
80
|
-
new CustomEvent(
|
|
94
|
+
new CustomEvent(event, {
|
|
81
95
|
detail: {
|
|
82
96
|
event: { category, action },
|
|
83
97
|
},
|
|
@@ -31,43 +31,51 @@ export default class TimerCountdown extends LitElement {
|
|
|
31
31
|
*/
|
|
32
32
|
this.loanRenewAtLast = 0;
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* store time when timer is started
|
|
36
|
+
* @type {string}
|
|
37
|
+
*/
|
|
38
|
+
this.timeWhenTimerStart = '';
|
|
39
|
+
|
|
34
40
|
/**
|
|
35
41
|
* delay seconds in setInterval function
|
|
36
42
|
* @type {number}
|
|
37
43
|
*/
|
|
38
|
-
this.timerExecutionSeconds =
|
|
44
|
+
this.timerExecutionSeconds = 60;
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
disconnectedCallback() {
|
|
42
48
|
window?.IALendingIntervals?.clearTimerCountdown();
|
|
43
49
|
}
|
|
44
50
|
|
|
51
|
+
firstUpdated() {
|
|
52
|
+
this.timerCountdown();
|
|
53
|
+
}
|
|
54
|
+
|
|
45
55
|
updated(changed) {
|
|
46
56
|
if (changed.has('secondsLeftOnLoan') && this.secondsLeftOnLoan > 0) {
|
|
47
|
-
this.disconnectedCallback();
|
|
48
|
-
|
|
49
57
|
this.timerCountdown();
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
timerCountdown() {
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
this.disconnectedCallback();
|
|
63
|
+
|
|
64
|
+
let secondsLeft = this.secondsLeftOnLoan;
|
|
65
|
+
|
|
66
|
+
// store current time
|
|
67
|
+
this.timeWhenTimerStart = new Date();
|
|
56
68
|
|
|
57
69
|
/**
|
|
58
70
|
* set interval in window object
|
|
59
71
|
* @see ia-lending-intervals.js
|
|
60
72
|
*/
|
|
61
|
-
window.IALendingIntervals.timerCountdown = setInterval(() => {
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
window.IALendingIntervals.timerCountdown = setInterval(async () => {
|
|
74
|
+
secondsLeft -= this.timerExecutionSeconds;
|
|
75
|
+
secondsLeft = Math.round(secondsLeft); // round number
|
|
64
76
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
secondsLeft,
|
|
68
|
-
' ||| timeLeftInMin',
|
|
69
|
-
Math.ceil(secondsLeft / 60)
|
|
70
|
-
);
|
|
77
|
+
// re-sync timer is gone off
|
|
78
|
+
await this.reSyncTimerIfGoneOff(secondsLeft);
|
|
71
79
|
|
|
72
80
|
/**
|
|
73
81
|
* execute from last 10th minute to 0th minute
|
|
@@ -76,26 +84,74 @@ export default class TimerCountdown extends LitElement {
|
|
|
76
84
|
* @see IABookActions::bindLoanRenewEvents
|
|
77
85
|
*/
|
|
78
86
|
if (secondsLeft <= this.loanRenewAtLast) {
|
|
79
|
-
this.
|
|
80
|
-
new CustomEvent('IABookActions:loanRenew', {
|
|
81
|
-
detail: {
|
|
82
|
-
hasPageChanged: false,
|
|
83
|
-
secondsLeft,
|
|
84
|
-
},
|
|
85
|
-
bubbles: true,
|
|
86
|
-
composed: true,
|
|
87
|
-
})
|
|
88
|
-
);
|
|
87
|
+
this.dispatchLoanRenewEvent(secondsLeft);
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
// clear interval
|
|
92
|
-
if (secondsLeft <=
|
|
90
|
+
// clear interval in secondsLeft if less
|
|
91
|
+
if (secondsLeft <= this.timerExecutionSeconds) {
|
|
93
92
|
this.disconnectedCallback();
|
|
94
93
|
window?.Sentry?.captureMessage(sentryLogs.clearOneHourTimer);
|
|
95
94
|
}
|
|
96
95
|
}, this.timerExecutionSeconds * 1000);
|
|
97
96
|
}
|
|
98
97
|
|
|
98
|
+
/**
|
|
99
|
+
* dispatch loan renew attempt event
|
|
100
|
+
*
|
|
101
|
+
* @param {number} secondsLeft
|
|
102
|
+
* @memberof TimerCountdown
|
|
103
|
+
*/
|
|
104
|
+
dispatchLoanRenewEvent(secondsLeft) {
|
|
105
|
+
this.dispatchEvent(
|
|
106
|
+
new CustomEvent('IABookActions:loanRenew', {
|
|
107
|
+
detail: {
|
|
108
|
+
hasPageChanged: false,
|
|
109
|
+
secondsLeft,
|
|
110
|
+
},
|
|
111
|
+
bubbles: true,
|
|
112
|
+
composed: true,
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* helper function to determine if timer is not in sync properly
|
|
119
|
+
*
|
|
120
|
+
* @param {number} timerSecondsLeft - actual seconds left get from setInterval
|
|
121
|
+
*
|
|
122
|
+
* @memberof TimerCountdown
|
|
123
|
+
*/
|
|
124
|
+
async reSyncTimerIfGoneOff(timerSecondsLeft) {
|
|
125
|
+
// debug info
|
|
126
|
+
console.log(
|
|
127
|
+
new Date().toLocaleTimeString(),
|
|
128
|
+
'timeLeftInSec',
|
|
129
|
+
timerSecondsLeft,
|
|
130
|
+
' ||| timeLeftInMin',
|
|
131
|
+
Math.ceil(timerSecondsLeft / 60)
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const currentTime = new Date();
|
|
135
|
+
|
|
136
|
+
// current time - loan time
|
|
137
|
+
const diffInSeconds =
|
|
138
|
+
currentTime.getTime() / 1000 - this.timeWhenTimerStart.getTime() / 1000;
|
|
139
|
+
|
|
140
|
+
const secondsShouldLeft = this.secondsLeftOnLoan - diffInSeconds;
|
|
141
|
+
|
|
142
|
+
// convert in minutes
|
|
143
|
+
const whatIsleft = Math.round(timerSecondsLeft);
|
|
144
|
+
const whatShouldLeft = Math.round(secondsShouldLeft);
|
|
145
|
+
|
|
146
|
+
if (whatIsleft !== whatShouldLeft) {
|
|
147
|
+
// debug info
|
|
148
|
+
console.log(
|
|
149
|
+
`timer is gone off, let's re-sync, whatIsleft -> ${whatIsleft}, whatShouldLeft -> ${whatShouldLeft}`
|
|
150
|
+
);
|
|
151
|
+
this.secondsLeftOnLoan = secondsShouldLeft; // the seconds should left in timer again
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
99
155
|
/**
|
|
100
156
|
* get remaining time with timeunit
|
|
101
157
|
*
|
|
@@ -13,7 +13,8 @@ export const analyticsCategories = {
|
|
|
13
13
|
export const analyticsActions = {
|
|
14
14
|
browse: 'Borrow-1Hour',
|
|
15
15
|
browseAgain: 'Borrow-Again',
|
|
16
|
-
|
|
16
|
+
browseAutoRenew: 'AutoRenewBook',
|
|
17
|
+
browseAutoReturn: 'AutoReturnBook',
|
|
17
18
|
borrow: 'Borrow-14Days',
|
|
18
19
|
waitlistJoin: 'JoinWaitlist',
|
|
19
20
|
waitlistLeave: 'LeaveWaitlist',
|
|
@@ -2,6 +2,7 @@ import { LitElement } from 'lit';
|
|
|
2
2
|
|
|
3
3
|
import { URLHelper } from '../../config/url-helper.js';
|
|
4
4
|
import { sentryLogs } from '../../config/sentry-events.js';
|
|
5
|
+
import { analyticsCategories } from '../../config/analytics-event-and-category.js';
|
|
5
6
|
|
|
6
7
|
import ActionsHandlerService from './actions-handler-service.js';
|
|
7
8
|
import * as Cookies from '../doc-cookies.js';
|
|
@@ -27,31 +28,50 @@ export default class ActionsHandler extends LitElement {
|
|
|
27
28
|
this.bindEvents();
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* reponsible to sent events to GA
|
|
33
|
+
*
|
|
34
|
+
* @param {string} eventCategory
|
|
35
|
+
* @param {string} eventAction
|
|
36
|
+
* @memberof ActionsHandler
|
|
37
|
+
*/
|
|
38
|
+
sendEvent(eventCategory, eventAction, label, extraParams) {
|
|
39
|
+
window?.archive_analytics?.send_event_no_sampling(
|
|
32
40
|
eventCategory,
|
|
33
41
|
eventAction,
|
|
34
|
-
`identifier=${this.identifier}
|
|
42
|
+
label || `identifier=${this.identifier}`,
|
|
43
|
+
extraParams
|
|
35
44
|
);
|
|
36
45
|
}
|
|
37
46
|
|
|
47
|
+
get getLoanCountStorageKey() {
|
|
48
|
+
return `br-browse-${this.identifier}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
bindEvents() {
|
|
39
52
|
this.addEventListener('browseBook', ({ detail }) => {
|
|
40
53
|
this.handleBrowseIt();
|
|
41
|
-
this.setConsecutiveLoanCounts();
|
|
54
|
+
this.setConsecutiveLoanCounts('browseBook');
|
|
42
55
|
const { category, action } = detail.event;
|
|
43
56
|
this.sendEvent(category, action);
|
|
44
57
|
});
|
|
45
58
|
|
|
46
59
|
this.addEventListener('browseBookAgain', ({ detail }) => {
|
|
47
60
|
this.handleBrowseIt();
|
|
48
|
-
this.setConsecutiveLoanCounts('
|
|
61
|
+
this.setConsecutiveLoanCounts('browseBookAgain');
|
|
62
|
+
const { category, action } = detail.event;
|
|
63
|
+
this.sendEvent(category, action);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
this.addEventListener('autoRenew', ({ detail }) => {
|
|
67
|
+
this.handleLoanRenewNow();
|
|
68
|
+
this.setConsecutiveLoanCounts('autoRenew');
|
|
49
69
|
const { category, action } = detail.event;
|
|
50
70
|
this.sendEvent(category, action);
|
|
51
71
|
});
|
|
52
72
|
|
|
53
|
-
this.addEventListener('
|
|
54
|
-
this.
|
|
73
|
+
this.addEventListener('autoReturn', ({ detail }) => {
|
|
74
|
+
this.setConsecutiveLoanCounts('autoReturn');
|
|
55
75
|
const { category, action } = detail.event;
|
|
56
76
|
this.sendEvent(category, action);
|
|
57
77
|
});
|
|
@@ -107,6 +127,100 @@ export default class ActionsHandler extends LitElement {
|
|
|
107
127
|
});
|
|
108
128
|
}
|
|
109
129
|
|
|
130
|
+
/**
|
|
131
|
+
* store consecutive one hour loan counts in cookies for GA
|
|
132
|
+
*
|
|
133
|
+
* There are two possible way of consecutive loan
|
|
134
|
+
* - book is browsed again just after getting expired
|
|
135
|
+
* - book loan is auto renewed for another hour
|
|
136
|
+
*
|
|
137
|
+
* @param {string} action - user action on book
|
|
138
|
+
* @return {void}
|
|
139
|
+
* @memberof ActionsHandler
|
|
140
|
+
*/
|
|
141
|
+
async setConsecutiveLoanCounts(action = '') {
|
|
142
|
+
try {
|
|
143
|
+
await this.getConsecutiveLoanRecord(action);
|
|
144
|
+
|
|
145
|
+
const date = new Date();
|
|
146
|
+
date.setHours(date.getHours() + 2); // 2 hours
|
|
147
|
+
|
|
148
|
+
// set new value
|
|
149
|
+
Cookies.setItem(
|
|
150
|
+
this.getLoanCountStorageKey,
|
|
151
|
+
JSON.stringify(this.lendingEventCounts),
|
|
152
|
+
date,
|
|
153
|
+
'/'
|
|
154
|
+
);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.log(error);
|
|
157
|
+
window?.Sentry?.captureException(
|
|
158
|
+
`${sentryLogs.setConsecutiveLoanCounts} - Error: ${error}`
|
|
159
|
+
);
|
|
160
|
+
this.sendEvent('Cookies-Error-Actions', error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get consecutive loan count records from cookies for GA
|
|
166
|
+
*
|
|
167
|
+
* @param {string} action
|
|
168
|
+
* @memberof ActionsHandler
|
|
169
|
+
*/
|
|
170
|
+
async getConsecutiveLoanRecord(action) {
|
|
171
|
+
const gaStats = { browse: 0, renew: 0, expire: 0 };
|
|
172
|
+
|
|
173
|
+
this.lendingEventCounts = JSON.parse(
|
|
174
|
+
Cookies.getItem(this.getLoanCountStorageKey)
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
let browse = this.lendingEventCounts?.browse ?? 0;
|
|
178
|
+
let renew = this.lendingEventCounts?.renew ?? 0;
|
|
179
|
+
let expire = this.lendingEventCounts?.expire ?? 0;
|
|
180
|
+
|
|
181
|
+
if (this.lendingEventCounts !== null) {
|
|
182
|
+
switch (action) {
|
|
183
|
+
case 'browseBook' || 'browseBookAgain':
|
|
184
|
+
browse = browse ? Number(browse) + 1 : 1;
|
|
185
|
+
gaStats.browse = browse;
|
|
186
|
+
break;
|
|
187
|
+
|
|
188
|
+
case 'autoRenew':
|
|
189
|
+
renew = renew ? Number(renew) + 1 : 1;
|
|
190
|
+
gaStats.renew = renew;
|
|
191
|
+
this.sendEvent(
|
|
192
|
+
analyticsCategories.browse,
|
|
193
|
+
`BookAutoRenewedFor${renew}`
|
|
194
|
+
);
|
|
195
|
+
break;
|
|
196
|
+
|
|
197
|
+
case 'autoReturn':
|
|
198
|
+
expire = expire ? Number(expire) + 1 : 1;
|
|
199
|
+
gaStats.expire = expire;
|
|
200
|
+
|
|
201
|
+
renew = 0; // reset renew count when book is expired
|
|
202
|
+
break;
|
|
203
|
+
default:
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// store these counts in cookies
|
|
209
|
+
this.lendingEventCounts = { browse, renew, expire };
|
|
210
|
+
|
|
211
|
+
// send google analytics events
|
|
212
|
+
this.sendEvent(
|
|
213
|
+
analyticsCategories.browse,
|
|
214
|
+
`browse${gaStats.browse}-autoRenew${gaStats.renew}-autoExpire${gaStats.expire}`,
|
|
215
|
+
'',
|
|
216
|
+
{
|
|
217
|
+
browse: gaStats.browse,
|
|
218
|
+
renew: gaStats.renew,
|
|
219
|
+
expire: gaStats.expire,
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
110
224
|
handleBrowseIt() {
|
|
111
225
|
const action = 'browse_book';
|
|
112
226
|
this.dispatchToggleActionGroup();
|
|
@@ -124,7 +238,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
124
238
|
});
|
|
125
239
|
}
|
|
126
240
|
|
|
127
|
-
|
|
241
|
+
handleLoanRenewNow() {
|
|
128
242
|
const action = 'renew_loan';
|
|
129
243
|
|
|
130
244
|
ActionsHandlerService({
|
|
@@ -271,31 +385,6 @@ export default class ActionsHandler extends LitElement {
|
|
|
271
385
|
}, this.waitUntillBorrowComplete * 1000);
|
|
272
386
|
}
|
|
273
387
|
|
|
274
|
-
// save consecutive loan count for borrow
|
|
275
|
-
async setConsecutiveLoanCounts(action = '') {
|
|
276
|
-
try {
|
|
277
|
-
let newCount = 1;
|
|
278
|
-
const storageKey = `loan-count-${this.identifier}`;
|
|
279
|
-
const existingCount = Cookies.getItem(storageKey);
|
|
280
|
-
|
|
281
|
-
// increase browse-count by 1 when you consecutive reading a book.
|
|
282
|
-
if (action === 'browseAgain' && existingCount !== undefined) {
|
|
283
|
-
newCount = existingCount ? Number(existingCount) + 1 : 1;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const date = new Date();
|
|
287
|
-
date.setHours(date.getHours() + 2); // 2 hours
|
|
288
|
-
|
|
289
|
-
// set new value
|
|
290
|
-
Cookies.setItem(storageKey, newCount, date, '/');
|
|
291
|
-
} catch (error) {
|
|
292
|
-
window?.Sentry?.captureException(
|
|
293
|
-
`${sentryLogs.setConsecutiveLoanCounts} - Error: ${error}`
|
|
294
|
-
);
|
|
295
|
-
this.sendEvent('Cookies-Error-Actions', error);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
388
|
/**
|
|
300
389
|
* set browse time in indexedDB
|
|
301
390
|
*/
|
|
@@ -62,7 +62,7 @@ export function setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
|
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* BROKEN Remove specific key's value from cookie
|
|
65
|
-
*
|
|
65
|
+
*
|
|
66
66
|
* @param {string} sKey cookie name
|
|
67
67
|
* @param {string} [sPath] path of current item
|
|
68
68
|
* @param {string} [sDomain]
|
|
@@ -81,3 +81,25 @@ export function removeItem(sKey, sPath, sDomain) {
|
|
|
81
81
|
|
|
82
82
|
return true;
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* determine if a specific cookie is exist
|
|
87
|
+
*
|
|
88
|
+
* @param {string} sKey cookie name
|
|
89
|
+
*
|
|
90
|
+
* @returns {boolean}
|
|
91
|
+
*/
|
|
92
|
+
export function hasItem(sKey) {
|
|
93
|
+
const reCNameAllowed = /^(?:expires|max\-age|path|domain|secure|samesite|httponly)$/i;
|
|
94
|
+
|
|
95
|
+
// eslint-disable-next-line
|
|
96
|
+
if (!sKey || reCNameAllowed.test(sKey)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return new RegExp(
|
|
101
|
+
'(?:^|;\\s*)' +
|
|
102
|
+
encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') +
|
|
103
|
+
'\\s*\\='
|
|
104
|
+
).test(document.cookie);
|
|
105
|
+
}
|
package/src/ia-book-actions.js
CHANGED
|
@@ -11,7 +11,6 @@ import './components/book-title-bar.js';
|
|
|
11
11
|
import './components/text-group.js';
|
|
12
12
|
import './components/info-icon.js';
|
|
13
13
|
import './components/timer-countdown.js';
|
|
14
|
-
import './core/config/ia-lending-intervals.js';
|
|
15
14
|
|
|
16
15
|
import { GetLendingActions } from './core/services/get-lending-actions.js';
|
|
17
16
|
import { mobileContainerWidth } from './core/config/constants.js';
|
|
@@ -19,6 +18,9 @@ import { sentryLogs } from './core/config/sentry-events.js';
|
|
|
19
18
|
import { LoanTokenPoller } from './core/services/loan-token-poller.js';
|
|
20
19
|
import { LoanRenewHelper } from './core/services/loan-renew-helper.js';
|
|
21
20
|
|
|
21
|
+
import './core/config/ia-lending-intervals.js';
|
|
22
|
+
import * as Cookies from './core/services/doc-cookies.js';
|
|
23
|
+
|
|
22
24
|
export const events = {
|
|
23
25
|
browseExpired: 'IABookReader:BrowsingHasExpired',
|
|
24
26
|
};
|
|
@@ -236,16 +238,10 @@ export default class IABookActions extends LitElement {
|
|
|
236
238
|
/**
|
|
237
239
|
* tokenPoller determines if user has loan token for this book
|
|
238
240
|
* - if book is going to renew, need to wait until renew is completed
|
|
239
|
-
* - otherwise execute immediately
|
|
240
241
|
*/
|
|
241
|
-
setTimeout(
|
|
242
|
-
()
|
|
243
|
-
|
|
244
|
-
},
|
|
245
|
-
|
|
246
|
-
// if book is renew while reading, let's wait to execute create-token api
|
|
247
|
-
this.loanRenewResult.renewNow ? this.tokenDelay * 1000 : 100
|
|
248
|
-
);
|
|
242
|
+
setTimeout(() => {
|
|
243
|
+
if (!hasExpired) this.startLoanTokenPoller();
|
|
244
|
+
}, 100);
|
|
249
245
|
}
|
|
250
246
|
|
|
251
247
|
/**
|
|
@@ -260,12 +256,12 @@ export default class IABookActions extends LitElement {
|
|
|
260
256
|
* dispatched this event from bookreader page changed
|
|
261
257
|
*/
|
|
262
258
|
window.addEventListener('BookReader:userAction', () => {
|
|
259
|
+
this.suppressToast = true;
|
|
260
|
+
this.closeToastManager();
|
|
261
|
+
|
|
263
262
|
if (this.borrowType === 'browsed') {
|
|
264
|
-
this.suppressToast = false;
|
|
265
263
|
this.autoLoanRenewChecker(true);
|
|
266
264
|
}
|
|
267
|
-
|
|
268
|
-
return nothing;
|
|
269
265
|
});
|
|
270
266
|
|
|
271
267
|
/**
|
|
@@ -320,6 +316,16 @@ export default class IABookActions extends LitElement {
|
|
|
320
316
|
this.loanRenewResult = this.loanRenewHelper.result;
|
|
321
317
|
}
|
|
322
318
|
|
|
319
|
+
/**
|
|
320
|
+
* close/hide toast message
|
|
321
|
+
*/
|
|
322
|
+
async closeToastManager() {
|
|
323
|
+
const toastTemplate = this.shadowRoot.querySelector('toast-template');
|
|
324
|
+
if (toastTemplate) {
|
|
325
|
+
toastTemplate?.remove();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
323
329
|
/**
|
|
324
330
|
* Show toast messages on some specific loan renew features. e.g.
|
|
325
331
|
* - show message when book is auto renewed
|
|
@@ -329,14 +335,11 @@ export default class IABookActions extends LitElement {
|
|
|
329
335
|
async showToastMessage() {
|
|
330
336
|
if (this.suppressToast) return;
|
|
331
337
|
|
|
332
|
-
|
|
333
|
-
if (!iaBookActions) return;
|
|
334
|
-
|
|
335
|
-
let toastTemplate = iaBookActions.querySelector('toast-template');
|
|
338
|
+
let toastTemplate = this.shadowRoot.querySelector('toast-template');
|
|
336
339
|
if (!toastTemplate) {
|
|
337
340
|
toastTemplate = document.createElement('toast-template');
|
|
338
341
|
}
|
|
339
|
-
await
|
|
342
|
+
await this.shadowRoot.appendChild(toastTemplate);
|
|
340
343
|
|
|
341
344
|
// if secondsLeft < 60, consider it 1 minute
|
|
342
345
|
let { secondsLeft } = this.loanRenewResult;
|
|
@@ -402,6 +405,9 @@ export default class IABookActions extends LitElement {
|
|
|
402
405
|
await this.localCache.delete(`${this.identifier}-loanTime`);
|
|
403
406
|
await this.localCache.delete(`${this.identifier}-pageChangedTime`);
|
|
404
407
|
|
|
408
|
+
// remove loan-renew-count-<identifier> cookie
|
|
409
|
+
Cookies.removeItem(`loan-renew-count-${this.identifier}`);
|
|
410
|
+
|
|
405
411
|
// show message after browsed book is expired.
|
|
406
412
|
this.loanRenewResult.renewNow = false;
|
|
407
413
|
this.loanRenewResult.texts =
|
|
@@ -484,7 +490,8 @@ export default class IABookActions extends LitElement {
|
|
|
484
490
|
.loanTotalTime=${this.loanRenewTimeConfig.loanTotalTime}
|
|
485
491
|
?hasAdminAccess=${this.hasAdminAccess}
|
|
486
492
|
?disabled=${this.disableActionGroup}
|
|
487
|
-
?
|
|
493
|
+
?autoRenew=${this.loanRenewResult.renewNow}
|
|
494
|
+
?autoReturn=${this.lendingStatus.browsingExpired}
|
|
488
495
|
@loanAutoRenewed=${this.handleLoanAutoRenewed}
|
|
489
496
|
@lendingActionError=${this.handleLendingActionError}
|
|
490
497
|
@toggleActionGroup=${this.handleToggleActionGroup}
|
|
@@ -573,8 +580,7 @@ export default class IABookActions extends LitElement {
|
|
|
573
580
|
* @param {string} event.detail.data.error - error message
|
|
574
581
|
*/
|
|
575
582
|
handleLendingActionError(event) {
|
|
576
|
-
|
|
577
|
-
this.handleToggleActionGroup();
|
|
583
|
+
this.disableActionGroup = false;
|
|
578
584
|
|
|
579
585
|
// clear all intervals for lending system when error occured
|
|
580
586
|
window?.IALendingIntervals?.clearAll();
|
|
@@ -582,7 +588,9 @@ export default class IABookActions extends LitElement {
|
|
|
582
588
|
const action = event?.detail?.action;
|
|
583
589
|
const errorMsg = event?.detail?.data?.error;
|
|
584
590
|
|
|
585
|
-
|
|
591
|
+
// template not show create_token errors
|
|
592
|
+
if (errorMsg && action !== 'create_token')
|
|
593
|
+
this.showErrorModal(errorMsg, action);
|
|
586
594
|
|
|
587
595
|
// if error related to loan token
|
|
588
596
|
// - clear tokenPoller interval
|
|
@@ -616,8 +624,6 @@ export default class IABookActions extends LitElement {
|
|
|
616
624
|
|
|
617
625
|
/* show error message if something went wrong */
|
|
618
626
|
async showErrorModal(errorMsg, action) {
|
|
619
|
-
this.disableActionGroup = false;
|
|
620
|
-
|
|
621
627
|
// check if this.modal passed as prop
|
|
622
628
|
if (!this.modal) {
|
|
623
629
|
this.modal = document.querySelector('modal-manager');
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en-GB">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="utf-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
7
|
-
<style>
|
|
8
|
-
html {
|
|
9
|
-
font-size: 10px;
|
|
10
|
-
/* This is to match petabox's base font size */
|
|
11
|
-
}
|
|
12
|
-
body {
|
|
13
|
-
margin: 0;
|
|
14
|
-
text-align: center;
|
|
15
|
-
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
16
|
-
}
|
|
17
|
-
#demo {
|
|
18
|
-
height: 50px;
|
|
19
|
-
}
|
|
20
|
-
ia-book-actions {
|
|
21
|
-
--white: #fff;
|
|
22
|
-
--black: #000;
|
|
23
|
-
--primaryBGColor: var(--black);
|
|
24
|
-
--secondaryBGColor: #222;
|
|
25
|
-
--tertiaryBGColor: #333;
|
|
26
|
-
--primaryTextColor: var(--white);
|
|
27
|
-
--primaryCTAFill: #194880;
|
|
28
|
-
--primaryCTABorder: #c5d1df;
|
|
29
|
-
--secondaryCTAFill: #333;
|
|
30
|
-
--secondaryCTABorder: #999;
|
|
31
|
-
--secondaryCTAFillRGB: 51, 51, 51;
|
|
32
|
-
--primaryErrorCTAFill: #e51c26;
|
|
33
|
-
--primaryErrorCTABorder: #f8c6c8;
|
|
34
|
-
--primaryCTAFillRGB: 25, 72, 128;
|
|
35
|
-
--primaryErrorCTAFillRGB: 229, 28, 38;
|
|
36
|
-
--primaryDisableCTAFill: #767676;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
fieldset {
|
|
40
|
-
width: fit-content;
|
|
41
|
-
margin-top: 50px;
|
|
42
|
-
}
|
|
43
|
-
fieldset legend {
|
|
44
|
-
text-align: left;
|
|
45
|
-
font-size: 12px;
|
|
46
|
-
}
|
|
47
|
-
td {
|
|
48
|
-
color: white;
|
|
49
|
-
font-size: 14px;
|
|
50
|
-
border-radius: 5%;
|
|
51
|
-
display: table-cell;
|
|
52
|
-
text-align: initial;
|
|
53
|
-
margin: 5px 0;
|
|
54
|
-
width: max-content;
|
|
55
|
-
display: block;
|
|
56
|
-
}
|
|
57
|
-
label {
|
|
58
|
-
padding: 10px;
|
|
59
|
-
display: block;
|
|
60
|
-
cursor: pointer;
|
|
61
|
-
margin: 2px;
|
|
62
|
-
background: #4e545a;
|
|
63
|
-
border-radius: 10px;
|
|
64
|
-
}
|
|
65
|
-
input[type="radio"], input[type="checkbox"] {
|
|
66
|
-
margin-top: 0;
|
|
67
|
-
vertical-align: middle;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.initial td {
|
|
71
|
-
float: left;
|
|
72
|
-
margin: 2px;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
body.modal-manager-open {
|
|
76
|
-
overflow: hidden;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
modal-manager[mode='closed'] {
|
|
80
|
-
display: none;
|
|
81
|
-
}
|
|
82
|
-
</style>
|
|
83
|
-
</head>
|
|
84
|
-
|
|
85
|
-
<body>
|
|
86
|
-
<ia-bookreader class="focus-on-child-only" signedin="" fullscreen="">
|
|
87
|
-
<div slot="header">
|
|
88
|
-
<ia-book-actions></ia-book-actions>
|
|
89
|
-
</div>
|
|
90
|
-
<div slot="main">
|
|
91
|
-
<div id="BookReader"></div>
|
|
92
|
-
</div>
|
|
93
|
-
</ia-bookreader>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<script type="module">
|
|
97
|
-
/* eslint-disable */
|
|
98
|
-
import '@internetarchive/bookreader';
|
|
99
|
-
import '@internetarchive/bookreader/BookReader/jquery-1.10.1.js';
|
|
100
|
-
import '@internetarchive/bookreader/BookReader/BookReader.js';
|
|
101
|
-
import '../src/ia-book-actions.js';
|
|
102
|
-
import {
|
|
103
|
-
defaultLendingStatus,
|
|
104
|
-
canBrowseAndBorrow,
|
|
105
|
-
} from '../src/assets/data/lending-get-status-service.js';
|
|
106
|
-
import { ModalConfig } from '@internetarchive/modal-manager';
|
|
107
|
-
|
|
108
|
-
const userid = '@neeraj-archive';
|
|
109
|
-
const identifier = 'naturalhistoryof00unse_4111';
|
|
110
|
-
let bwbPurchaseUrl = 'https://www.betterworldbooks.com/product/detail/cambridge-ancient-hist-v04-0521044863';
|
|
111
|
-
|
|
112
|
-
let iaBookActions = document.querySelector('ia-book-actions');
|
|
113
|
-
|
|
114
|
-
// for debugging
|
|
115
|
-
window.iaBookActions = iaBookActions;
|
|
116
|
-
|
|
117
|
-
const modalConfig = new ModalConfig();
|
|
118
|
-
modalConfig.headerColor = '#d9534f';
|
|
119
|
-
|
|
120
|
-
let lendingBarPostInit = function lendingBarPostInit() {
|
|
121
|
-
setTimeout(function() {
|
|
122
|
-
console.log('executed', 'br.init()');
|
|
123
|
-
}, 100);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
127
|
-
iaBookActions.userid = userid;
|
|
128
|
-
iaBookActions.identifier = identifier;
|
|
129
|
-
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
130
|
-
iaBookActions.lendingStatus = canBrowseAndBorrow;
|
|
131
|
-
iaBookActions.bwbPurchaseUrl = '';
|
|
132
|
-
iaBookActions.modalConfig = modalConfig;
|
|
133
|
-
iaBookActions.lendingBarPostInit = lendingBarPostInit;
|
|
134
|
-
iaBookActions.tokenDelay = 2000; // 2 seconds
|
|
135
|
-
iaBookActions.returnUrl = 'https://openlibrary.org';
|
|
136
|
-
|
|
137
|
-
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
138
|
-
|
|
139
|
-
const manifest = await fetch('https://ia801302.us.archive.org/BookReader/BookReaderJSIA.php?id=goody&itemPath=/29/items/goody&server=ia801302.us.archive.org&format=jsonp&subPrefix=goody&requestUri=/details/goody/mode/1up%3Fview%3Dtheater%26ui%3Dembed%26wrapper%3Dfalse');
|
|
140
|
-
|
|
141
|
-
console.log('manifest ****', manifest).then(res => res.json());
|
|
142
|
-
</script>
|
|
143
|
-
|
|
144
|
-
</div>
|
|
145
|
-
</body>
|
|
146
|
-
</html>
|