@internetarchive/ia-book-actions 0.0.5-3 → 0.0.5-4-03

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
@@ -83,12 +83,7 @@
83
83
  import '../src/ia-book-actions.js';
84
84
  import {
85
85
  defaultLendingStatus,
86
- canBrowse,
87
- browsed,
88
86
  canBrowseAndBorrow,
89
- browsedAndBorrow,
90
- canBrowseAndBorrowod,
91
- canBrowseAndJoinWaitlistForBorrow,
92
87
  } from '../src/assets/data/lending-get-status-service.js';
93
88
 
94
89
  const userid = '@neeraj-archive';
@@ -100,11 +95,23 @@
100
95
  // set defaultLendingStatus for unavailable (without borrowables) book
101
96
  iaBookActions.userid = '';
102
97
  iaBookActions.identifier = identifier;
98
+ iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
103
99
  iaBookActions.lendingStatus = defaultLendingStatus;
104
100
  iaBookActions.bwbPurchaseUrl = '';
101
+ iaBookActions.barType = '';
105
102
 
106
103
  let lendingStatus1 = iaBookActions.lendingStatus;
107
104
 
105
+ document.querySelectorAll('.titleBar input[type=checkbox]').forEach((item) => {
106
+ item.addEventListener('click', (e) => {
107
+ if (e.target.checked) {
108
+ iaBookActions.barType = 'title';
109
+ } else {
110
+ iaBookActions.barType = 'action';
111
+ }
112
+ });
113
+ });
114
+
108
115
  document.querySelectorAll('.userState input[type=checkbox]').forEach((item) => {
109
116
  item.addEventListener('click', (e) => {
110
117
  if (e.target.checked) {
@@ -139,6 +146,13 @@
139
146
  if (e.target.value === 'user_has_browsed') {
140
147
  lendingStatus1.user_has_browsed = true;
141
148
  lendingStatus1.available_to_browse = false;
149
+ lendingStatus1.secondsLeftOnLoan = 10;
150
+ lendingStatus1.browsingExpired = false;
151
+ } else if(e.target.value === 'browsingExpired') {
152
+ lendingStatus1.user_has_browsed = true;
153
+ lendingStatus1.available_to_browse = false;
154
+ lendingStatus1.secondsLeftOnLoan = 0;
155
+ lendingStatus1.browsingExpired = true;
142
156
  } else if (e.target.value === 'available_to_browse') {
143
157
  lendingStatus1.available_to_browse = true;
144
158
  lendingStatus1.user_has_browsed = false;
@@ -192,7 +206,18 @@
192
206
 
193
207
  <div>
194
208
  <fieldset>
195
- <legend>Dev try for lending banner</legend>
209
+ <legend>Dev testing for book title bar</legend>
210
+ <table class="initial">
211
+ <tr>
212
+ <td class="titleBar">
213
+ <label><input type="checkbox" name="title" value="title" />Title Bar</label>
214
+ </td>
215
+ </tr>
216
+ </table>
217
+ </fieldset>
218
+
219
+ <fieldset>
220
+ <legend>Dev testing for book action bar</legend>
196
221
  <table class="initial">
197
222
  <tr>
198
223
  <td class="userState">
@@ -206,6 +231,7 @@
206
231
  <td class="availableToBrowse">
207
232
  <label><input type="radio" name="browse" value="available_to_browse" />available_to_browse</label>
208
233
  <label><input type="radio" name="browse" value="user_has_browsed" />user_has_browsed</label>
234
+ <label><input type="radio" name="browse" value="browsingExpired" />browsingExpired</label>
209
235
  </td>
210
236
  <td class="availableToBorrow">
211
237
  <label><input type="radio" name="borrow" value="available_to_borrow" />available_to_borrow</label>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-book-actions",
3
- "version": "0.0.5-3",
3
+ "version": "0.0.5-4-03",
4
4
  "description": "Bookreader actions for borrowable book",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -0,0 +1,32 @@
1
+ import { html } from 'lit-element';
2
+
3
+ export const archiveLogo = html`
4
+ <svg
5
+ class="ia-logo"
6
+ width="26"
7
+ height="26"
8
+ viewBox="0 0 27 30"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ aria-labelledby="logoTitleID logoDescID"
11
+ >
12
+ <title id="logoTitleID">Internet Archive logo</title>
13
+ <desc id="logoDescID">
14
+ A line drawing of the Internet Archive headquarters building façade.
15
+ </desc>
16
+ <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
17
+ <mask id="mask-2" fill="white">
18
+ <path
19
+ d="M26.6666667,28.6046512 L26.6666667,30 L0,30 L0.000283687943,28.6046512 L26.6666667,28.6046512 Z M25.6140351,26.5116279 L25.6140351,28.255814 L1.05263158,28.255814 L1.05263158,26.5116279 L25.6140351,26.5116279 Z M3.62469203,7.6744186 L3.91746909,7.82153285 L4.0639977,10.1739544 L4.21052632,13.9963932 L4.21052632,17.6725617 L4.0639977,22.255044 L4.03962296,25.3421929 L3.62469203,25.4651163 L2.16024641,25.4651163 L1.72094074,25.3421929 L1.55031755,22.255044 L1.40350877,17.6970339 L1.40350877,14.0211467 L1.55031755,10.1739544 L1.68423854,7.80887484 L1.98962322,7.6744186 L3.62469203,7.6744186 Z M24.6774869,7.6744186 L24.9706026,7.82153285 L25.1168803,10.1739544 L25.2631579,13.9963932 L25.2631579,17.6725617 L25.1168803,22.255044 L25.0927809,25.3421929 L24.6774869,25.4651163 L23.2130291,25.4651163 L22.7736357,25.3421929 L22.602418,22.255044 L22.4561404,17.6970339 L22.4561404,14.0211467 L22.602418,10.1739544 L22.7369262,7.80887484 L23.0420916,7.6744186 L24.6774869,7.6744186 Z M9.94042303,7.6744186 L10.2332293,7.82153285 L10.3797725,10.1739544 L10.5263158,13.9963932 L10.5263158,17.6725617 L10.3797725,22.255044 L10.3556756,25.3421929 L9.94042303,25.4651163 L8.47583122,25.4651163 L8.0362015,25.3421929 L7.86556129,22.255044 L7.71929825,17.6970339 L7.71929825,14.0211467 L7.86556129,10.1739544 L8.00005604,7.80887484 L8.30491081,7.6744186 L9.94042303,7.6744186 Z M18.0105985,7.6744186 L18.3034047,7.82153285 L18.449948,10.1739544 L18.5964912,13.9963932 L18.5964912,17.6725617 L18.449948,22.255044 L18.425851,25.3421929 L18.0105985,25.4651163 L16.5460067,25.4651163 L16.1066571,25.3421929 L15.9357367,22.255044 L15.7894737,17.6970339 L15.7894737,14.0211467 L15.9357367,10.1739544 L16.0702315,7.80887484 L16.3753664,7.6744186 L18.0105985,7.6744186 Z M25.6140351,4.53488372 L25.6140351,6.97674419 L1.05263158,6.97674419 L1.05263158,4.53488372 L25.6140351,4.53488372 Z M13.0806755,0 L25.9649123,2.93331338 L25.4484139,3.8372093 L0.771925248,3.8372093 L0,3.1041615 L13.0806755,0 Z"
20
+ id="path-1"
21
+ ></path>
22
+ </mask>
23
+ <use fill="#FFFFFF" xlink:href="#path-1"></use>
24
+ <g mask="url(#mask-2)" fill="#FFFFFF">
25
+ <path
26
+ d="M0,0 L26.6666667,0 L26.6666667,30 L0,30 L0,0 Z"
27
+ id="swatch"
28
+ ></path>
29
+ </g>
30
+ </g>
31
+ </svg>
32
+ `;
@@ -34,6 +34,7 @@ export const defaultLendingStatus = {
34
34
  users_on_waitlist: 0,
35
35
  // userid: "",
36
36
  bookUrl: '/details/practicalorganic00plim',
37
+ browsingExpired: false,
37
38
  daysLeftOnLoan: 0,
38
39
  isAdmin: false,
39
40
  isArchiveOrgLending: true,
@@ -47,7 +48,7 @@ export const defaultLendingStatus = {
47
48
  loanRecord: [],
48
49
  loansUrl: '/details/@neeraj-archive?tab=loans#loans-on-loan',
49
50
  maxLoans: 10,
50
- secondsLeftOnLoan: 0,
51
+ secondsLeftOnLoan: 10,
51
52
  shouldProtectImages: true,
52
53
  totalWaitlistCount: 0,
53
54
  userHasBorrowed: false,
@@ -58,139 +59,6 @@ export const defaultLendingStatus = {
58
59
  userWaitlistPosition: -1,
59
60
  userid: '@neeraj-archive',
60
61
  };
61
-
62
- export const canBrowse = {
63
- active_borrows: 0,
64
- active_browses: 0,
65
- available_borrowable_copies: 0,
66
- available_browsable_copies: 1,
67
- available_lendable_copies: 1,
68
- available_to_borrow: false,
69
- available_to_browse: true,
70
- available_to_waitlist: false,
71
- copies_reserved_for_waitlist: 0,
72
- is_lendable: true,
73
- is_login_required: false,
74
- is_printdisabled: true,
75
- is_readable: false,
76
- last_borrow: null,
77
- last_browse: null,
78
- last_waitlist: null,
79
- max_borrowable_copies: 0,
80
- max_browsable_copies: 1,
81
- max_lendable_copies: 1,
82
- next_borrow_expiration: null,
83
- next_browse_expiration: null,
84
- orphaned_acs_loans: 0,
85
- upgradable_browses: 0,
86
- user_at_max_loans: false,
87
- user_can_claim_waitlist: false,
88
- user_has_acs_borrowed: false,
89
- user_has_borrowed: false,
90
- user_has_browsed: false,
91
- user_is_printdisabled: false,
92
- user_loan_count: 0,
93
- user_loan_record: [],
94
- user_on_waitlist: false,
95
- users_on_waitlist: 0,
96
- // userid: "",
97
- bookUrl: '/details/practicalorganic00plim',
98
- daysLeftOnLoan: 0,
99
- isAdmin: false,
100
- isArchiveOrgLending: true,
101
- isAvailable: false,
102
- isAvailableForBrowsing: true,
103
- isBrowserBorrowable: true,
104
- isLendingRequired: true,
105
- isOpenLibraryLending: false,
106
- isPrintDisabledOnly: false,
107
- loanCount: 0,
108
- loanRecord: [],
109
- loansUrl: '/details/@neeraj-archive?tab=loans#loans-on-loan',
110
- maxLoans: 10,
111
- secondsLeftOnLoan: 0,
112
- shouldProtectImages: true,
113
- totalWaitlistCount: 0,
114
- userHasBorrowed: false,
115
- userHasBrowsed: false,
116
- userHoldIsReady: false,
117
- userIsPrintDisabled: false,
118
- userOnWaitingList: false,
119
- userWaitlistPosition: -1,
120
- userid: '@neeraj-archive',
121
- };
122
-
123
- export const browsed = {
124
- active_borrows: 0,
125
- active_browses: 1,
126
- available_borrowable_copies: 0,
127
- available_browsable_copies: 0,
128
- available_lendable_copies: 0,
129
- available_to_borrow: false,
130
- available_to_browse: false,
131
- available_to_waitlist: false,
132
- copies_reserved_for_waitlist: 0,
133
- is_lendable: true,
134
- is_login_required: false,
135
- is_printdisabled: true,
136
- is_readable: false,
137
- last_borrow: null,
138
- last_browse: '2021-07-30 09:57:40',
139
- last_waitlist: null,
140
- max_borrowable_copies: 0,
141
- max_browsable_copies: 1,
142
- max_lendable_copies: 1,
143
- next_borrow_expiration: null,
144
- next_browse_expiration: '2021-07-30 10:57:40',
145
- orphaned_acs_loans: 0,
146
- upgradable_browses: 0,
147
- user_at_max_loans: false,
148
- user_can_claim_waitlist: false,
149
- user_has_acs_borrowed: false,
150
- user_has_borrowed: false,
151
- user_has_browsed: true,
152
- user_is_printdisabled: false,
153
- user_loan_count: 1,
154
- user_loan_record: {
155
- userid: '@neeraj-archive',
156
- listname: 'loan',
157
- identifier: 'practicalorganic00plim',
158
- },
159
- user_on_waitlist: false,
160
- users_on_waitlist: 0,
161
- // userid: "",
162
- bookUrl: '/details/practicalorganic00plim',
163
- daysLeftOnLoan: 0,
164
- isAdmin: false,
165
- isArchiveOrgLending: true,
166
- isAvailable: false,
167
- isAvailableForBrowsing: false,
168
- isBrowserBorrowable: true,
169
- isLendingRequired: true,
170
- isOpenLibraryLending: false,
171
- isPrintDisabledOnly: false,
172
- loanCount: 1,
173
- loanId: '1ca15f92d07dfdae3f7b1516084aec5d603800b8',
174
- loanRecord: {
175
- userid: '@neeraj-archive',
176
- listname: 'loan',
177
- identifier: 'practicalorganic00plim',
178
- },
179
- loanStartDate: '2021-07-30 09:57:40',
180
- loansUrl: '/details/@neeraj-archive?tab=loans#loans-on-loan',
181
- maxLoans: 10,
182
- secondsLeftOnLoan: 3591,
183
- shouldProtectImages: true,
184
- totalWaitlistCount: 0,
185
- userHasBorrowed: false,
186
- userHasBrowsed: true,
187
- userHoldIsReady: false,
188
- userIsPrintDisabled: false,
189
- userOnWaitingList: false,
190
- userWaitlistPosition: -1,
191
- userid: '@neeraj-archive',
192
- };
193
-
194
62
  export const canBrowseAndBorrow = {
195
63
  active_borrows: 0,
196
64
  active_browses: 1,
@@ -261,206 +129,3 @@ export const canBrowseAndBorrow = {
261
129
  userWaitlistPosition: -1,
262
130
  userid: '@neeraj-archive',
263
131
  };
264
-
265
- export const browsedAndBorrow = {
266
- active_borrows: 0,
267
- active_browses: 1,
268
- available_borrowable_copies: 0,
269
- available_browsable_copies: 0,
270
- available_lendable_copies: 0,
271
- available_to_borrow: true,
272
- available_to_browse: true,
273
- available_to_waitlist: false,
274
- copies_reserved_for_waitlist: 0,
275
- is_lendable: true,
276
- is_login_required: false,
277
- is_printdisabled: true,
278
- is_readable: false,
279
- last_borrow: null,
280
- last_browse: '2021-07-30 09:57:40',
281
- last_waitlist: null,
282
- max_borrowable_copies: 0,
283
- max_browsable_copies: 1,
284
- max_lendable_copies: 1,
285
- next_borrow_expiration: null,
286
- next_browse_expiration: '2021-07-30 10:57:40',
287
- orphaned_acs_loans: 0,
288
- upgradable_browses: 0,
289
- user_at_max_loans: false,
290
- user_can_claim_waitlist: false,
291
- user_has_acs_borrowed: false,
292
- user_has_borrowed: false,
293
- user_has_browsed: true,
294
- user_is_printdisabled: false,
295
- user_loan_count: 1,
296
- user_loan_record: {
297
- userid: '@neeraj-archive',
298
- listname: 'loan',
299
- identifier: 'practicalorganic00plim',
300
- },
301
- user_on_waitlist: false,
302
- users_on_waitlist: 0,
303
- // userid: "",
304
- bookUrl: '/details/practicalorganic00plim',
305
- daysLeftOnLoan: 0,
306
- isAdmin: false,
307
- isArchiveOrgLending: true,
308
- isAvailable: false,
309
- isAvailableForBrowsing: false,
310
- isBrowserBorrowable: true,
311
- isLendingRequired: true,
312
- isOpenLibraryLending: false,
313
- isPrintDisabledOnly: false,
314
- loanCount: 1,
315
- loanId: '1ca15f92d07dfdae3f7b1516084aec5d603800b8',
316
- loanRecord: {
317
- userid: '@neeraj-archive',
318
- listname: 'loan',
319
- identifier: 'practicalorganic00plim',
320
- },
321
- loanStartDate: '2021-07-30 09:57:40',
322
- loansUrl: '/details/@neeraj-archive?tab=loans#loans-on-loan',
323
- maxLoans: 10,
324
- secondsLeftOnLoan: 3591,
325
- shouldProtectImages: true,
326
- totalWaitlistCount: 0,
327
- userHasBorrowed: false,
328
- userHasBrowsed: true,
329
- userHoldIsReady: false,
330
- userIsPrintDisabled: false,
331
- userOnWaitingList: false,
332
- userWaitlistPosition: -1,
333
- userid: '@neeraj-archive',
334
- };
335
-
336
- export const canBrowseAndBorrowod = {
337
- active_borrows: 0,
338
- active_browses: 1,
339
- available_borrowable_copies: 0,
340
- available_browsable_copies: 0,
341
- available_lendable_copies: 0,
342
- available_to_borrow: true,
343
- available_to_browse: true,
344
- available_to_waitlist: false,
345
- copies_reserved_for_waitlist: 0,
346
- is_lendable: true,
347
- is_login_required: false,
348
- is_printdisabled: true,
349
- is_readable: false,
350
- last_borrow: null,
351
- last_browse: '2021-07-30 09:57:40',
352
- last_waitlist: null,
353
- max_borrowable_copies: 0,
354
- max_browsable_copies: 1,
355
- max_lendable_copies: 1,
356
- next_borrow_expiration: null,
357
- next_browse_expiration: '2021-07-30 10:57:40',
358
- orphaned_acs_loans: 0,
359
- upgradable_browses: 0,
360
- user_at_max_loans: false,
361
- user_can_claim_waitlist: false,
362
- user_has_acs_borrowed: false,
363
- user_has_borrowed: true,
364
- user_has_browsed: false,
365
- user_is_printdisabled: false,
366
- user_loan_count: 1,
367
- user_loan_record: {
368
- userid: '@neeraj-archive',
369
- listname: 'loan',
370
- identifier: 'practicalorganic00plim',
371
- },
372
- user_on_waitlist: false,
373
- users_on_waitlist: 0,
374
- // userid: "",
375
- bookUrl: '/details/practicalorganic00plim',
376
- daysLeftOnLoan: 0,
377
- isAdmin: false,
378
- isArchiveOrgLending: true,
379
- isAvailable: false,
380
- isAvailableForBrowsing: false,
381
- isBrowserBorrowable: true,
382
- isLendingRequired: true,
383
- isOpenLibraryLending: false,
384
- isPrintDisabledOnly: false,
385
- loanCount: 1,
386
- loanId: '1ca15f92d07dfdae3f7b1516084aec5d603800b8',
387
- loanRecord: {
388
- userid: '@neeraj-archive',
389
- listname: 'loan',
390
- identifier: 'practicalorganic00plim',
391
- },
392
- loanStartDate: '2021-07-30 09:57:40',
393
- loansUrl: '/details/@neeraj-archive?tab=loans#loans-on-loan',
394
- maxLoans: 10,
395
- secondsLeftOnLoan: 3591,
396
- shouldProtectImages: true,
397
- totalWaitlistCount: 0,
398
- userHasBorrowed: false,
399
- userHasBrowsed: true,
400
- userHoldIsReady: false,
401
- userIsPrintDisabled: false,
402
- userOnWaitingList: false,
403
- userWaitlistPosition: -1,
404
- userid: '@neeraj-archive',
405
- };
406
-
407
- export const canBrowseAndJoinWaitlistForBorrow = {
408
- active_borrows: 1,
409
- active_browses: 0,
410
- available_borrowable_copies: 0,
411
- available_browsable_copies: 1,
412
- available_lendable_copies: 1,
413
- available_to_borrow: false,
414
- available_to_browse: true,
415
- available_to_waitlist: true,
416
- copies_reserved_for_waitlist: 0,
417
- is_lendable: true,
418
- is_login_required: false,
419
- is_printdisabled: true,
420
- is_readable: false,
421
- last_borrow: '2021-07-24 18:17:46',
422
- last_browse: null,
423
- last_waitlist: '2021-07-27 11:03:23',
424
- max_borrowable_copies: 1,
425
- max_browsable_copies: 2,
426
- max_lendable_copies: 2,
427
- next_borrow_expiration: '2021-08-02 18:29:41',
428
- next_browse_expiration: null,
429
- orphaned_acs_loans: 0,
430
- upgradable_browses: 0,
431
- user_at_max_loans: false,
432
- user_can_claim_waitlist: false,
433
- user_has_acs_borrowed: false,
434
- user_has_borrowed: false,
435
- user_has_browsed: false,
436
- user_is_printdisabled: false,
437
- user_loan_count: 0,
438
- user_loan_record: [],
439
- user_on_waitlist: false,
440
- users_on_waitlist: 2,
441
- // userid: "",
442
- bookUrl: '/details/worldletitutio0000vish',
443
- daysLeftOnLoan: 0,
444
- isAdmin: false,
445
- isArchiveOrgLending: true,
446
- isAvailable: false,
447
- isAvailableForBrowsing: true,
448
- isBrowserBorrowable: true,
449
- isLendingRequired: true,
450
- isOpenLibraryLending: false,
451
- isPrintDisabledOnly: false,
452
- loanCount: 0,
453
- loanRecord: [],
454
- loansUrl: '/details/@neeraj-archive?tab=loans#loans-on-loan',
455
- maxLoans: 10,
456
- secondsLeftOnLoan: 0,
457
- shouldProtectImages: true,
458
- totalWaitlistCount: 2,
459
- userHasBorrowed: false,
460
- userHasBrowsed: false,
461
- userHoldIsReady: false,
462
- userIsPrintDisabled: false,
463
- userOnWaitingList: false,
464
- userWaitlistPosition: -1,
465
- userid: '@neeraj-archive',
466
- };
@@ -3,6 +3,8 @@ import { css } from 'lit-element';
3
3
  export default css`
4
4
  :host {
5
5
  display: inline-flex;
6
+ height: 3.5rem;
7
+ padding: 1rem 0;
6
8
  }
7
9
  .action-buttons {
8
10
  display: inline-flex;
@@ -0,0 +1,93 @@
1
+ import { html, css } from 'lit-element';
2
+
3
+ import {
4
+ analyticsCategories,
5
+ analyticsActions,
6
+ } from '../core/config/analytics-event-and-category.js';
7
+ import ActionsHandler from '../core/services/actions-handler/actions-handler.js';
8
+
9
+ import { archiveLogo } from '../assets/data/archive-logo.js';
10
+
11
+ export class BookTitleBar extends ActionsHandler {
12
+ static get properties() {
13
+ return {
14
+ identifier: { type: String },
15
+ bookTitle: { type: String },
16
+ };
17
+ }
18
+
19
+ constructor() {
20
+ super();
21
+ this.identifier = '';
22
+ this.bookTitle = '';
23
+ this.analyticsCategories = analyticsCategories;
24
+ this.analyticsActions = analyticsActions;
25
+ }
26
+
27
+ /**
28
+ * Click handler to emit custom event on action click
29
+ */
30
+ clickHandler() {
31
+ const { category, action } = {
32
+ category: this.analyticsCategories.bookReaderHeader,
33
+ action: this.analyticsActions.titleBar,
34
+ };
35
+
36
+ this.dispatchEvent(
37
+ new CustomEvent('bookTitleBar', {
38
+ detail: {
39
+ event: { category, action },
40
+ },
41
+ })
42
+ );
43
+ }
44
+
45
+ render() {
46
+ return html`
47
+ <a
48
+ class="embed-link"
49
+ @click=${() => {
50
+ this.clickHandler();
51
+ }}
52
+ href="/details/${this.identifier}"
53
+ >
54
+ <span>${archiveLogo}</span>
55
+ <span class="title">${this.bookTitle}</span>
56
+ </a>
57
+ `;
58
+ }
59
+
60
+ static get styles() {
61
+ return css`
62
+ :host {
63
+ padding: 0 10px;
64
+ height: 3.4rem;
65
+ display: flex;
66
+ }
67
+ .embed-link {
68
+ display: inline-flex;
69
+ align-items: center;
70
+ text-decoration: none;
71
+ color: var(--primaryTextColor, #fff);
72
+ font-size: 1.4rem;
73
+ }
74
+ .embed-link .title {
75
+ display: -webkit-box;
76
+ -webkit-box-orient: vertical;
77
+ -webkit-line-clamp: 2;
78
+ overflow: hidden;
79
+ text-align: left;
80
+ line-height: initial;
81
+ }
82
+ .embed-link svg {
83
+ margin-right: 0.5rem;
84
+ display: block;
85
+ }
86
+ .embed-link:hover {
87
+ text-decoration: underline;
88
+ }
89
+ `;
90
+ }
91
+ }
92
+
93
+ window.customElements.define('book-title-bar', BookTitleBar);
@@ -6,9 +6,8 @@ export const analyticsCategories = {
6
6
  browse: 'BookReader-ReadingBrowse',
7
7
  preview: 'BookReader-Preview',
8
8
  satisfactionMetric: 'DetailsPage-Book',
9
- purchase: 'BookReaderHeader',
10
- unavailable: 'BookReader-Preview',
11
- admin: 'Admin',
9
+ bookReaderHeader: 'BookReader-Header',
10
+ adminAccess: 'Admin-Access',
12
11
  };
13
12
 
14
13
  export const analyticsActions = {
@@ -21,4 +20,6 @@ export const analyticsActions = {
21
20
  login: 'LogIn',
22
21
  purchase: 'BWBPurchase',
23
22
  unavailable: 'Book-Unavailable',
23
+ printDisability: 'Print-Disability',
24
+ titleBar: 'Book-Title-Bar',
24
25
  };
@@ -33,7 +33,7 @@ export default class ActionsConfig {
33
33
  this.analyticsActions = analyticsActions;
34
34
  }
35
35
 
36
- browseBookConfig() {
36
+ firstBrowseConfig() {
37
37
  return {
38
38
  id: 'browseBook',
39
39
  text: 'Borrow for 1 hour',
@@ -45,10 +45,22 @@ export default class ActionsConfig {
45
45
  };
46
46
  }
47
47
 
48
+ browseAgainConfig() {
49
+ return {
50
+ id: 'browseBookAgain',
51
+ text: 'Borrow again',
52
+ className: 'primary',
53
+ analyticsEvent: {
54
+ category: this.analyticsCategories.browse,
55
+ action: this.analyticsActions.browseAgain,
56
+ },
57
+ };
58
+ }
59
+
48
60
  returnBookConfig() {
49
61
  const eventCategory = this.lendingStatus.user_has_browsed
50
- ? 'browse'
51
- : 'borrow';
62
+ ? this.analyticsCategories.browse
63
+ : this.analyticsCategories.borrow;
52
64
 
53
65
  return {
54
66
  id: 'returnNow',
@@ -77,7 +89,7 @@ export default class ActionsConfig {
77
89
  analyticsEvent: {
78
90
  category: this.lendingStatus.user_has_browsed
79
91
  ? this.analyticsCategories.browse
80
- : this.analyticsCategories.borrow,
92
+ : this.analyticsCategories.preview,
81
93
  action: this.analyticsActions.borrow,
82
94
  },
83
95
  };
@@ -161,7 +173,7 @@ export default class ActionsConfig {
161
173
  target: '_blank',
162
174
  className: 'purchase dark',
163
175
  analyticsEvent: {
164
- category: this.analyticsCategories.purchase,
176
+ category: this.analyticsCategories.bookReaderHeader,
165
177
  action: this.analyticsActions.purchase,
166
178
  },
167
179
  };
@@ -179,8 +191,8 @@ export default class ActionsConfig {
179
191
  target: '_self',
180
192
  className: 'print-disability',
181
193
  analyticsEvent: {
182
- category: this.analyticsCategories.purchase,
183
- action: this.analyticsActions.purchase,
194
+ category: this.analyticsCategories.bookReaderHeader,
195
+ action: this.analyticsActions.printDisability,
184
196
  },
185
197
  };
186
198
  }
@@ -198,7 +210,7 @@ export default class ActionsConfig {
198
210
  target: '_self',
199
211
  className: 'danger',
200
212
  analyticsEvent: {
201
- category: this.analyticsCategories.admin,
213
+ category: this.analyticsCategories.adminAccess,
202
214
  action: this.analyticsActions.borrow,
203
215
  },
204
216
  };
@@ -216,7 +228,7 @@ export default class ActionsConfig {
216
228
  target: '_self',
217
229
  className: 'ia-button',
218
230
  analyticsEvent: {
219
- category: this.analyticsCategories.admin,
231
+ category: this.analyticsCategories.adminAccess,
220
232
  action: this.analyticsActions.doneBorrowing,
221
233
  },
222
234
  };
@@ -229,7 +241,7 @@ export default class ActionsConfig {
229
241
  className: 'primary unavailable',
230
242
  disabled: true,
231
243
  analyticsEvent: {
232
- category: this.analyticsCategories.unavailable,
244
+ category: this.analyticsCategories.preview,
233
245
  action: this.analyticsActions.unavailable,
234
246
  },
235
247
  };
@@ -82,6 +82,11 @@ export default class ActionsHandler extends LitElement {
82
82
  const { category, action } = detail.event;
83
83
  this.sendEvent(category, action);
84
84
  });
85
+
86
+ this.addEventListener('bookTitleBar', ({ detail }) => {
87
+ const { category, action } = detail.event;
88
+ this.sendEvent(category, action);
89
+ });
85
90
  }
86
91
 
87
92
  handleBrowseIt() {
@@ -2,7 +2,6 @@
2
2
  /* eslint no-console: "off" */
3
3
  /* eslint no-nested-ternary: "off" */
4
4
  /* eslint-disable */
5
- import { nothing } from 'lit-html';
6
5
  import { URLHelper } from '../config/url-helper.js';
7
6
  import {
8
7
  analyticsCategories,
@@ -104,7 +103,7 @@ export default class GetLendingActions {
104
103
  const leaveWaitlist = this.actionsConfig.leaveWaitlistConfig();
105
104
  const borrowBook = this.actionsConfig.borrowBookConfig();
106
105
  const browseBook = lendingStatus.available_to_browse
107
- ? this.actionsConfig.browseBookConfig()
106
+ ? this.actionsConfig.firstBrowseConfig()
108
107
  : null;
109
108
 
110
109
  const dropdownOptions = browseBook ? [browseBook, borrowBook] : [];
@@ -150,7 +149,7 @@ export default class GetLendingActions {
150
149
  primaryTitle: 'You are on the waitlist for this book.',
151
150
  primaryActions: [
152
151
  this.actionsConfig.leaveWaitlistConfig(),
153
- this.actionsConfig.browseBookConfig(),
152
+ this.actionsConfig.firstBrowseConfig(),
154
153
  ],
155
154
  primaryColor: 'primary',
156
155
  secondaryActions: [
@@ -200,7 +199,9 @@ export default class GetLendingActions {
200
199
  borrow = this.actionsConfig.unavailableBookConfig();
201
200
  }
202
201
 
203
- const actions = [borrow, waitlist].filter(action => {
202
+ const printDisability = this.actionsConfig.printDisabilityConfig();
203
+
204
+ const actions = [borrow, waitlist, printDisability].filter(action => {
204
205
  return action !== null;
205
206
  });
206
207
 
@@ -263,25 +264,9 @@ export default class GetLendingActions {
263
264
  : possibleTitles.one_hour;
264
265
 
265
266
  // one hour borrow config
266
- const oneHrBorrowText = browsingHasExpired
267
- ? 'Borrow again'
268
- : 'Borrow for 1 hour';
269
- const browseAgainEvent = {
270
- category: this.analyticsCategories.browse,
271
- action: this.analyticsActions.browseAgain,
272
- };
273
- const firstBrowseEvent = {
274
- category: this.analyticsCategories.preview,
275
- action: this.analyticsActions.browse,
276
- };
277
- const oneHrBorrowEvent = browsingHasExpired
278
- ? browseAgainEvent
279
- : firstBrowseEvent;
280
-
281
- const oneHrBorrow = this.actionsConfig.browseBookConfig(
282
- oneHrBorrowText,
283
- oneHrBorrowEvent
284
- );
267
+ const oneHrBorrow = browsingHasExpired
268
+ ? this.actionsConfig.browseAgainConfig()
269
+ : this.actionsConfig.firstBrowseConfig();
285
270
 
286
271
  const borrow = this.actionsConfig.borrowBookConfig();
287
272
  const waitlist = this.actionsConfig.waitlistConfig();
@@ -316,10 +301,7 @@ export default class GetLendingActions {
316
301
  return this.loggedOutOptions();
317
302
  }
318
303
 
319
- const canBrowse =
320
- lendingStatus.available_to_browse ||
321
- (!lendingStatus.available_to_browse && lendingStatus.browsingExpired);
322
- if (canBrowse) {
304
+ if (lendingStatus.available_to_browse || lendingStatus.browsingExpired) {
323
305
  return this.borrow1HrAction();
324
306
  }
325
307
 
@@ -386,7 +368,8 @@ export default class GetLendingActions {
386
368
  lendingStatus.user_is_printdisabled;
387
369
 
388
370
  const patronIsReading =
389
- lendingStatus.user_has_borrowed || lendingStatus.user_has_browsed;
371
+ lendingStatus.user_has_borrowed ||
372
+ (lendingStatus.user_has_browsed && !lendingStatus.browsingExpired);
390
373
 
391
374
  const notBorrowed =
392
375
  !lendingStatus.user_has_borrowed && !lendingStatus.user_has_browsed;
@@ -422,7 +405,7 @@ export default class GetLendingActions {
422
405
  lendingActions = this.leaveWaitlistAction();
423
406
  } else if (userCanAccessPrintDisabled) {
424
407
  lendingActions = this.borrowPrintDisabledAction();
425
- } else if (canBorrow) {
408
+ } else if (canBorrow || lendingStatus.browsingExpired) {
426
409
  lendingActions = this.borrowAction();
427
410
  } else if (lendingStatus.isPrintDisabledOnly) {
428
411
  lendingActions = this.onlyPrintDisabledAction();
@@ -1,8 +1,10 @@
1
+ /* eslint-disable camelcase */
1
2
  import { html, css, LitElement } from 'lit-element';
2
3
 
3
4
  import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
4
5
 
5
6
  import './components/collapsible-action-group.js';
7
+ import './components/book-title-bar.js';
6
8
  import './components/text-group.js';
7
9
  import './components/info-icon.js';
8
10
 
@@ -14,9 +16,11 @@ export default class IABookActions extends LitElement {
14
16
  return {
15
17
  userid: { type: String },
16
18
  identifier: { type: String },
19
+ bookTitle: { type: String },
17
20
  lendingStatus: { type: Object },
18
21
  width: { type: Number },
19
22
  bwbPurchaseUrl: { type: String },
23
+ barType: { type: String },
20
24
  sharedObserver: { attribute: false },
21
25
  };
22
26
  }
@@ -25,15 +29,17 @@ export default class IABookActions extends LitElement {
25
29
  super();
26
30
  this.userid = '';
27
31
  this.identifier = '';
32
+ this.bookTitle = '';
28
33
  this.lendingStatus = {};
34
+ this.width = 0;
35
+ this.bwbPurchaseUrl = '';
36
+ this.barType = 'action'; // 'title'|'action'
37
+ this.sharedObserver = undefined;
29
38
  this.primaryActions = [];
30
39
  this.primaryTitle = '';
31
40
  this.primaryColor = 'primary';
32
41
  this.secondaryActions = [];
33
- this.width = 0;
34
- this.bwbPurchaseUrl = '';
35
- this.lendingOptions = [];
36
- this.sharedObserver = undefined;
42
+ this.lendingOptions = {};
37
43
  }
38
44
 
39
45
  disconnectedCallback() {
@@ -60,6 +66,28 @@ export default class IABookActions extends LitElement {
60
66
  }
61
67
  }
62
68
 
69
+ browseHasExpired() {
70
+ const browsingExpired = true;
71
+ const currStatus = { ...this.lendingStatus, browsingExpired };
72
+ this.lendingStatus = currStatus;
73
+ }
74
+
75
+ startBrowseTimer() {
76
+ const {
77
+ browsingExpired,
78
+ user_has_browsed,
79
+ secondsLeftOnLoan,
80
+ } = this.lendingStatus;
81
+ if (!user_has_browsed || browsingExpired) {
82
+ return;
83
+ }
84
+
85
+ const timeLeft = secondsLeftOnLoan * 1000;
86
+ setTimeout(() => {
87
+ this.browseHasExpired();
88
+ }, timeLeft);
89
+ }
90
+
63
91
  /** SharedObserver resize handler */
64
92
  handleResize(entry) {
65
93
  // if you are observing multiple targets,
@@ -111,26 +139,46 @@ export default class IABookActions extends LitElement {
111
139
  this.secondaryActions = actions.secondaryActions.filter(action => {
112
140
  return action != null;
113
141
  });
142
+
143
+ if (
144
+ this.lendingStatus.user_has_browsed &&
145
+ !this.lendingStatus.browseHasExpired
146
+ ) {
147
+ this.startBrowseTimer();
148
+ }
114
149
  }
115
150
 
116
151
  render() {
117
152
  return html`
118
153
  <section class="lending-wrapper">
119
- <collapsible-action-group
120
- .userid=${this.userid}
121
- .identifier=${this.identifier}
122
- .primaryColor=${this.primaryColor}
123
- .primaryActions=${this.primaryActions}
124
- .secondaryActions=${this.secondaryActions}
125
- .width=${this.width}
126
- .hasAdminAccess=${this.hasAdminAccess}
127
- >
128
- </collapsible-action-group>
129
- ${this.textGroupTemplate} ${this.infoIconTemplate}
154
+ ${this.barType === 'title' ? this.bookTitleBar : this.bookActionBar}
130
155
  </section>
131
156
  `;
132
157
  }
133
158
 
159
+ get bookTitleBar() {
160
+ return html`<book-title-bar
161
+ .identifier=${this.identifier}
162
+ .bookTitle=${this.bookTitle}
163
+ ></book-title-bar>`;
164
+ }
165
+
166
+ get bookActionBar() {
167
+ return html`
168
+ <collapsible-action-group
169
+ .userid=${this.userid}
170
+ .identifier=${this.identifier}
171
+ .primaryColor=${this.primaryColor}
172
+ .primaryActions=${this.primaryActions}
173
+ .secondaryActions=${this.secondaryActions}
174
+ .width=${this.width}
175
+ .hasAdminAccess=${this.hasAdminAccess}
176
+ >
177
+ </collapsible-action-group>
178
+ ${this.textGroupTemplate} ${this.infoIconTemplate}
179
+ `;
180
+ }
181
+
134
182
  get iconClass() {
135
183
  return this.width <= mobileContainerWidth ? 'mobile' : 'desktop';
136
184
  }
@@ -146,7 +194,7 @@ export default class IABookActions extends LitElement {
146
194
  get textGroupTemplate() {
147
195
  return html`<text-group
148
196
  textClass=${this.textClass}
149
- texts="${this.primaryTitle}"
197
+ texts=${this.primaryTitle}
150
198
  >
151
199
  </text-group>`;
152
200
  }
@@ -165,7 +213,6 @@ export default class IABookActions extends LitElement {
165
213
  .lending-wrapper {
166
214
  width: 100%;
167
215
  margin: 0 auto;
168
- padding: 10px 0;
169
216
  display: inline-flex;
170
217
  align-items: center;
171
218
  justify-content: center;
@@ -0,0 +1,39 @@
1
+ import { html, fixture, expect, oneEvent } from '@open-wc/testing';
2
+ import '../../src/components/book-title-bar.js';
3
+
4
+ const container = ({ identifier, bookTitle } = {}) =>
5
+ html`<book-title-bar
6
+ .identifier=${identifier}
7
+ .bookTitle=${bookTitle}
8
+ ></book-title-bar>`;
9
+
10
+ describe('<book-title-bar>', () => {
11
+ it('check inner texts of title bar', async () => {
12
+ const el = await fixture(
13
+ container({
14
+ identifier: 'goody',
15
+ bookTitle: 'this is test booktitle',
16
+ })
17
+ );
18
+ const link = el.shadowRoot.querySelector('a');
19
+ expect(link.innerText).to.equal('this is test booktitle');
20
+ expect(link.getAttribute('href')).to.equal('/details/goody');
21
+ });
22
+
23
+ it('check if event if firing on valid analytics category action', async () => {
24
+ const el = await fixture(
25
+ container({
26
+ identifier: 'goody',
27
+ bookTitle: 'this is test booktitle',
28
+ })
29
+ );
30
+
31
+ const clickButton = () =>
32
+ el.shadowRoot.querySelector('a').dispatchEvent(new Event('click'));
33
+ setTimeout(clickButton);
34
+
35
+ const { detail } = await oneEvent(el, 'bookTitleBar');
36
+ expect(detail.event.category).to.equal('BookReader-Header');
37
+ expect(detail.event.action).to.equal('Book-Title-Bar');
38
+ });
39
+ });
@@ -36,7 +36,7 @@ describe('Get Lending Actions', () => {
36
36
  );
37
37
  const actions = lendingOptions.getCurrentLendingActions();
38
38
 
39
- expect(actions.primaryActions.length).to.equal(1);
39
+ expect(actions.primaryActions.length).to.equal(2);
40
40
  expect(actions.primaryTitle).to.equal(
41
41
  'This book can be borrowed for 14 days.'
42
42
  );
@@ -1,4 +1,5 @@
1
- import { html, fixture, expect } from '@open-wc/testing';
1
+ import { html, fixture, expect, aTimeout } from '@open-wc/testing';
2
+
2
3
  import '../src/ia-book-actions.js';
3
4
  import Sinon from 'sinon';
4
5
 
@@ -126,7 +127,7 @@ describe('Borrow status actions', () => {
126
127
  expect(el.primaryTitle).to.equal(
127
128
  'Renewable every hour, pending availability.'
128
129
  );
129
- expect(el.primaryActions.length).to.equal(1);
130
+ expect(el.primaryActions.length).to.equal(2);
130
131
  expect(el.primaryActions[0].text).to.equal('Log In and Borrow');
131
132
  expect(el.primaryActions[0].text).to.equal(expectedPrimaryActions[0].text);
132
133
  });
@@ -159,40 +160,79 @@ describe('Borrow status actions', () => {
159
160
  expect(el.primaryActions[0].text).to.equal(expectedPrimaryActions[0].text);
160
161
  expect(el.primaryActions[1].text).to.equal('Borrow for 14 days');
161
162
  });
163
+ });
162
164
 
163
- describe('Shared Resize Observer', () => {
164
- it('can receive a Shared Resize Observer', async () => {
165
- const sharedObserverStub = new SharedResizeObserver();
166
- const addObserverSpy = Sinon.spy(sharedObserverStub, 'addObserver');
167
- const component = await fixture(html` <ia-book-actions
168
- .userid=${'@userid'}
169
- .identifier=${'foo'}
170
- .lendingStatus=${{
165
+ describe('Browsing expired status', () => {
166
+ it('Book is browsed but not expired', async () => {
167
+ const el = await fixture(
168
+ container({
169
+ userid: '@userid',
170
+ lendingStatus: {
171
171
  is_lendable: true,
172
172
  user_has_browsed: true,
173
- available_to_browse: true,
174
- available_to_borrow: true,
175
- }}
176
- .sharedObserver=${sharedObserverStub}
177
- ></ia-book-actions>`);
178
- await component.updateComplete;
179
-
180
- expect(addObserverSpy.callCount).to.equal(1);
181
- });
182
- it('loads its own resize observer if it is not received', async () => {
183
- const component = await fixture(html` <ia-book-actions
184
- .userid=${'@userid'}
185
- .identifier=${'foo'}
186
- .lendingStatus=${{
173
+ browseHasExpired: false,
174
+ },
175
+ })
176
+ );
177
+ expect(el.primaryTitle).contains('Borrow ends at ');
178
+ expect(el.primaryActions[0].text).to.equal('Return now');
179
+ expect(el.primaryActions[1].text).to.equal('Print Disability Access');
180
+ });
181
+
182
+ it('Book is browsing and going to expire after 1 second', async () => {
183
+ const el = await fixture(
184
+ container({
185
+ userid: '@userid',
186
+ lendingStatus: {
187
187
  is_lendable: true,
188
188
  user_has_browsed: true,
189
- available_to_browse: true,
190
- available_to_borrow: true,
191
- }}
192
- ></ia-book-actions>`);
189
+ browseHasExpired: false,
190
+ secondsLeftOnLoan: 1,
191
+ },
192
+ })
193
+ );
194
+
195
+ await aTimeout(1500); // wait for 1.5 second
196
+ el.updateComplete;
197
+
198
+ expect(el.primaryTitle).contains('Your loan has expired.');
199
+ expect(el.primaryActions[0].text).to.equal('Borrow again');
200
+ });
201
+ });
202
+
203
+ describe('Shared Resize Observer', () => {
204
+ it('can receive a Shared Resize Observer', async () => {
205
+ const sharedObserverStub = new SharedResizeObserver();
206
+ const addObserverSpy = Sinon.spy(sharedObserverStub, 'addObserver');
207
+ const component = await fixture(html` <ia-book-actions
208
+ .userid=${'@userid'}
209
+ .identifier=${'foo'}
210
+ .lendingStatus=${{
211
+ is_lendable: true,
212
+ user_has_browsed: true,
213
+ available_to_browse: true,
214
+ available_to_borrow: true,
215
+ }}
216
+ .sharedObserver=${sharedObserverStub}
217
+ ></ia-book-actions>`);
218
+ await component.updateComplete;
219
+
220
+ expect(addObserverSpy.callCount).to.equal(1);
221
+ });
193
222
 
194
- await component.updateComplete;
195
- expect(component.sharedObserver).to.not.be.undefined;
196
- });
223
+ it('loads its own resize observer if it is not received', async () => {
224
+ const component = await fixture(html` <ia-book-actions
225
+ .userid=${'@userid'}
226
+ .identifier=${'foo'}
227
+ .lendingStatus=${{
228
+ is_lendable: true,
229
+ user_has_browsed: true,
230
+ available_to_browse: true,
231
+ available_to_borrow: true,
232
+ }}
233
+ ></ia-book-actions>`);
234
+
235
+ await component.updateComplete;
236
+ expect(component.sharedObserver).to.not.be.undefined;
197
237
  });
198
238
  });