@internetarchive/ia-topnav 1.3.6 → 1.3.7

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.
Files changed (85) hide show
  1. package/.eslintrc +16 -16
  2. package/LICENSE +661 -661
  3. package/README.md +147 -147
  4. package/index.d.ts +109 -109
  5. package/index.js +3 -3
  6. package/package.json +61 -61
  7. package/src/assets/img/hamburger.js +38 -38
  8. package/src/assets/img/ia-icon.js +33 -33
  9. package/src/assets/img/icon-audio.js +23 -23
  10. package/src/assets/img/icon-close.js +16 -16
  11. package/src/assets/img/icon-donate-unpadded.js +16 -16
  12. package/src/assets/img/icon-donate.js +15 -15
  13. package/src/assets/img/icon-ellipses.js +15 -15
  14. package/src/assets/img/icon-ia-logo.js +22 -22
  15. package/src/assets/img/icon-images.js +15 -15
  16. package/src/assets/img/icon-search.js +15 -15
  17. package/src/assets/img/icon-software.js +15 -15
  18. package/src/assets/img/icon-texts.js +15 -15
  19. package/src/assets/img/icon-upload-unpadded.js +14 -14
  20. package/src/assets/img/icon-upload.js +15 -15
  21. package/src/assets/img/icon-user.js +15 -15
  22. package/src/assets/img/icon-video.js +15 -15
  23. package/src/assets/img/icon-web.js +15 -15
  24. package/src/assets/img/icon.js +18 -18
  25. package/src/assets/img/icons.js +33 -33
  26. package/src/assets/img/wordmark-stacked.js +13 -13
  27. package/src/data/menus.js +646 -646
  28. package/src/desktop-subnav.js +45 -45
  29. package/src/dropdown-menu.js +110 -109
  30. package/src/ia-topnav.js +324 -314
  31. package/src/lib/formatUrl.js +1 -1
  32. package/src/lib/keyboard-navigation.js +128 -0
  33. package/src/lib/location-handler.js +5 -5
  34. package/src/lib/query-handler.js +7 -7
  35. package/src/lib/toSentenceCase.js +8 -8
  36. package/src/login-button.js +79 -79
  37. package/src/media-button.js +113 -113
  38. package/src/media-menu.js +154 -133
  39. package/src/media-slider.js +118 -104
  40. package/src/media-subnav.js +112 -112
  41. package/src/more-slider.js +33 -33
  42. package/src/nav-search.js +111 -117
  43. package/src/primary-nav.js +258 -224
  44. package/src/save-page-form.js +59 -59
  45. package/src/search-menu.js +145 -115
  46. package/src/signed-out-dropdown.js +10 -10
  47. package/src/styles/base.js +48 -48
  48. package/src/styles/desktop-subnav.js +37 -37
  49. package/src/styles/dropdown-menu.js +168 -166
  50. package/src/styles/ia-topnav.js +87 -87
  51. package/src/styles/login-button.js +82 -79
  52. package/src/styles/media-button.js +156 -156
  53. package/src/styles/media-menu.js +66 -70
  54. package/src/styles/media-slider.js +81 -81
  55. package/src/styles/media-subnav.js +156 -156
  56. package/src/styles/more-slider.js +15 -15
  57. package/src/styles/nav-search.js +136 -136
  58. package/src/styles/primary-nav.js +311 -300
  59. package/src/styles/save-page-form.js +54 -54
  60. package/src/styles/search-menu.js +105 -99
  61. package/src/styles/signed-out-dropdown.js +31 -31
  62. package/src/styles/user-menu.js +31 -31
  63. package/src/styles/wayback-search.js +48 -48
  64. package/src/styles/wayback-slider.js +30 -30
  65. package/src/tracked-element.js +29 -27
  66. package/src/user-menu.js +56 -42
  67. package/src/wayback-search.js +18 -18
  68. package/src/wayback-slider.js +87 -87
  69. package/test/assets/img/hamburger.test.js +15 -15
  70. package/test/assets/img/user.test.js +15 -15
  71. package/test/data/menus.test.js +19 -19
  72. package/test/dropdown-menu.test.js +25 -25
  73. package/test/ia-icon.test.js +13 -13
  74. package/test/ia-topnav.test.js +273 -273
  75. package/test/login-button.test.js +15 -15
  76. package/test/media-button.test.js +19 -19
  77. package/test/media-menu.test.js +40 -40
  78. package/test/media-slider.test.js +57 -57
  79. package/test/more-slider.test.js +13 -13
  80. package/test/nav-search.test.js +61 -61
  81. package/test/primary-nav.test.js +82 -82
  82. package/test/save-page-form.test.js +35 -35
  83. package/test/search-menu.test.js +49 -49
  84. package/test/user-menu.test.js +33 -33
  85. package/test/wayback-slider.test.js +80 -80
@@ -1,112 +1,112 @@
1
- import { html } from 'https://offshoot.prod.archive.org/lit.js';
2
- import TrackedElement from './tracked-element.js';
3
- import './wayback-slider.js';
4
- import './more-slider.js';
5
- import mediaSubnavCSS from './styles/media-subnav.js';
6
- import toSentenceCase from './lib/toSentenceCase.js';
7
- import formatUrl from './lib/formatUrl.js';
8
-
9
- class MediaSubnav extends TrackedElement {
10
- static get styles() {
11
- return mediaSubnavCSS;
12
- }
13
-
14
- static get properties() {
15
- return {
16
- baseHost: { type: String },
17
- config: { type: Object },
18
- menu: { type: String },
19
- menuItems: { type: Object },
20
- };
21
- }
22
-
23
- constructor() {
24
- super();
25
-
26
- this.config = {};
27
- this.menu = '';
28
- this.menuItems = {};
29
-
30
- // Begin properties not monitored by LitElement
31
- this.links = MediaSubnav.defaultLinks;
32
- }
33
-
34
- shouldUpdate() {
35
- if (this.menuItems) {
36
- this.links = this.menuItems;
37
- }
38
- return true;
39
- }
40
-
41
- static get defaultLinks() {
42
- return { iconLinks: [], featuredLinks: [], links: [] };
43
- }
44
-
45
- analyticsEvent(title) {
46
- return `${this.config.eventCategory}|${toSentenceCase(title)}${toSentenceCase(this.menu)}`;
47
- }
48
-
49
- get iconLinks() {
50
- return this.links.iconLinks.map(link => (
51
- html`
52
- <a href="${formatUrl(link.url, this.baseHost)}" @click=${this.trackClick} data-event-click-tracking="${this.analyticsEvent(link.title)}"><img src="${link.icon}" loading="lazy" />${link.title}</a>
53
- `
54
- ));
55
- }
56
-
57
- renderLinks(category) {
58
- return this.links[category].map(link => (
59
- html`
60
- <li><a href="${formatUrl(link.url, this.baseHost)}" @click=${this.trackClick} data-event-click-tracking="${this.analyticsEvent(link.title)}">${link.title}</a></li>
61
- `
62
- ));
63
- }
64
-
65
- render() {
66
- if (!this.menu) {
67
- return html``;
68
- }
69
-
70
- if (this.menuItems) {
71
- this.links = this.menuItems;
72
- }
73
-
74
- if (this.menu === 'web') {
75
- return html`
76
- <wayback-slider
77
- .baseHost=${this.baseHost}
78
- .config=${this.config}
79
- .archiveItLinks=${this.menuItems.archiveItLinks}
80
- .browserExtensionsLinks=${this.menuItems.browserExtensionsLinks}
81
- .mobileAppsLinks=${this.menuItems.mobileAppsLinks}
82
- ></wayback-slider>`;
83
- }
84
-
85
- if (this.menu === 'more') {
86
- return html`
87
- <more-slider .baseHost=${this.baseHost} .config=${this.config} .menuItems=${this.menuItems}>
88
- </more-slider>`;
89
- }
90
-
91
- return html`
92
- <h3>${this.links.heading}</h3>
93
- <div class="icon-links">
94
- ${this.iconLinks}
95
- </div>
96
- <div class="links featured">
97
- <h4>Featured</h4>
98
- <ul>
99
- ${this.renderLinks('featuredLinks')}
100
- </ul>
101
- </div>
102
- <div class="links top">
103
- <h4>Top</h4>
104
- <ul>
105
- ${this.renderLinks('links')}
106
- </ul>
107
- </div>
108
- `;
109
- }
110
- }
111
-
112
- customElements.define('media-subnav', MediaSubnav);
1
+ import { html } from 'https://offshoot.prod.archive.org/lit.js';
2
+ import TrackedElement from './tracked-element.js';
3
+ import './wayback-slider.js';
4
+ import './more-slider.js';
5
+ import mediaSubnavCSS from './styles/media-subnav.js';
6
+ import toSentenceCase from './lib/toSentenceCase.js';
7
+ import formatUrl from './lib/formatUrl.js';
8
+
9
+ class MediaSubnav extends TrackedElement {
10
+ static get styles() {
11
+ return mediaSubnavCSS;
12
+ }
13
+
14
+ static get properties() {
15
+ return {
16
+ baseHost: { type: String },
17
+ config: { type: Object },
18
+ menu: { type: String },
19
+ menuItems: { type: Object },
20
+ };
21
+ }
22
+
23
+ constructor() {
24
+ super();
25
+
26
+ this.config = {};
27
+ this.menu = '';
28
+ this.menuItems = {};
29
+
30
+ // Begin properties not monitored by LitElement
31
+ this.links = MediaSubnav.defaultLinks;
32
+ }
33
+
34
+ shouldUpdate() {
35
+ if (this.menuItems) {
36
+ this.links = this.menuItems;
37
+ }
38
+ return true;
39
+ }
40
+
41
+ static get defaultLinks() {
42
+ return { iconLinks: [], featuredLinks: [], links: [] };
43
+ }
44
+
45
+ analyticsEvent(title) {
46
+ return `${this.config.eventCategory}|${toSentenceCase(title)}${toSentenceCase(this.menu)}`;
47
+ }
48
+
49
+ get iconLinks() {
50
+ return this.links.iconLinks.map(link => (
51
+ html`
52
+ <a href="${formatUrl(link.url, this.baseHost)}" @click=${this.trackClick} data-event-click-tracking="${this.analyticsEvent(link.title)}"><img src="${link.icon}" loading="lazy" />${link.title}</a>
53
+ `
54
+ ));
55
+ }
56
+
57
+ renderLinks(category) {
58
+ return this.links[category].map(link => (
59
+ html`
60
+ <li><a href="${formatUrl(link.url, this.baseHost)}" @click=${this.trackClick} data-event-click-tracking="${this.analyticsEvent(link.title)}">${link.title}</a></li>
61
+ `
62
+ ));
63
+ }
64
+
65
+ render() {
66
+ if (!this.menu) {
67
+ return html``;
68
+ }
69
+
70
+ if (this.menuItems) {
71
+ this.links = this.menuItems;
72
+ }
73
+
74
+ if (this.menu === 'web') {
75
+ return html`
76
+ <wayback-slider
77
+ .baseHost=${this.baseHost}
78
+ .config=${this.config}
79
+ .archiveItLinks=${this.menuItems.archiveItLinks}
80
+ .browserExtensionsLinks=${this.menuItems.browserExtensionsLinks}
81
+ .mobileAppsLinks=${this.menuItems.mobileAppsLinks}
82
+ ></wayback-slider>`;
83
+ }
84
+
85
+ if (this.menu === 'more') {
86
+ return html`
87
+ <more-slider .baseHost=${this.baseHost} .config=${this.config} .menuItems=${this.menuItems}>
88
+ </more-slider>`;
89
+ }
90
+
91
+ return html`
92
+ <h3>${this.links.heading}</h3>
93
+ <div class="icon-links">
94
+ ${this.iconLinks}
95
+ </div>
96
+ <div class="links featured">
97
+ <h4>Featured</h4>
98
+ <ul>
99
+ ${this.renderLinks('featuredLinks')}
100
+ </ul>
101
+ </div>
102
+ <div class="links top">
103
+ <h4>Top</h4>
104
+ <ul>
105
+ ${this.renderLinks('links')}
106
+ </ul>
107
+ </div>
108
+ `;
109
+ }
110
+ }
111
+
112
+ customElements.define('media-subnav', MediaSubnav);
@@ -1,33 +1,33 @@
1
- import { html } from 'https://offshoot.prod.archive.org/lit.js';
2
- import TrackedElement from './tracked-element.js';
3
- import toSentenceCase from './lib/toSentenceCase.js';
4
- import moreSliderCSS from './styles/more-slider.js';
5
- import formatUrl from './lib/formatUrl.js';
6
-
7
- class MoreSlider extends TrackedElement {
8
- static get properties() {
9
- return {
10
- baseHost: { type: String },
11
- config: { type: Object },
12
- menuItems: { type: Array },
13
- };
14
- }
15
-
16
- static get styles() {
17
- return moreSliderCSS;
18
- }
19
-
20
- analyticsEvent(title) {
21
- return `${this.config.eventCategory}|NavMore${toSentenceCase(title)}`;
22
- }
23
-
24
- render() {
25
- return html`
26
- <ul>
27
- ${this.menuItems.map(item => html`<li><a @click=${this.trackClick} href=${formatUrl(item.url, this.baseHost)} data-event-click-tracking="${this.analyticsEvent(item.title)}">${item.title}</a></li>`)}
28
- </ul>
29
- `;
30
- }
31
- }
32
-
33
- customElements.define('more-slider', MoreSlider);
1
+ import { html } from 'https://offshoot.prod.archive.org/lit.js';
2
+ import TrackedElement from './tracked-element.js';
3
+ import toSentenceCase from './lib/toSentenceCase.js';
4
+ import moreSliderCSS from './styles/more-slider.js';
5
+ import formatUrl from './lib/formatUrl.js';
6
+
7
+ class MoreSlider extends TrackedElement {
8
+ static get properties() {
9
+ return {
10
+ baseHost: { type: String },
11
+ config: { type: Object },
12
+ menuItems: { type: Array },
13
+ };
14
+ }
15
+
16
+ static get styles() {
17
+ return moreSliderCSS;
18
+ }
19
+
20
+ analyticsEvent(title) {
21
+ return `${this.config.eventCategory}|NavMore${toSentenceCase(title)}`;
22
+ }
23
+
24
+ render() {
25
+ return html`
26
+ <ul>
27
+ ${this.menuItems.map(item => html`<li><a @click=${this.trackClick} href=${formatUrl(item.url, this.baseHost)} data-event-click-tracking="${this.analyticsEvent(item.title)}">${item.title}</a></li>`)}
28
+ </ul>
29
+ `;
30
+ }
31
+ }
32
+
33
+ customElements.define('more-slider', MoreSlider);
package/src/nav-search.js CHANGED
@@ -1,117 +1,111 @@
1
- import { nothing, html } from 'https://offshoot.prod.archive.org/lit.js';
2
-
3
- import TrackedElement from './tracked-element.js';
4
- import navSearchCSS from './styles/nav-search.js';
5
- import icons from './assets/img/icons.js';
6
- import formatUrl from './lib/formatUrl.js';
7
-
8
- class NavSearch extends TrackedElement {
9
- static get styles() {
10
- return navSearchCSS;
11
- }
12
-
13
- static get properties() {
14
- return {
15
- baseHost: { type: String },
16
- config: { type: Object },
17
- locationHandler: { type: Object },
18
- open: { type: Boolean },
19
- openMenu: { type: String },
20
- searchIn: { type: String },
21
- searchQuery: { type: String },
22
- };
23
- }
24
-
25
- constructor() {
26
- super();
27
- this.config = {};
28
- this.locationHandler = () => {};
29
- this.open = false;
30
- this.openMenu = '';
31
- this.searchIn = '';
32
- }
33
-
34
- updated() {
35
- if (this.open) {
36
- this.shadowRoot.querySelector('[name=query]').focus();
37
- }
38
- return true;
39
- }
40
-
41
- search(e) {
42
- const query = this.shadowRoot.querySelector('[name=query]').value;
43
-
44
- if (!query) {
45
- e.preventDefault();
46
- return false;
47
- }
48
-
49
- // TV search points to a detail page with a q param instead
50
- if (this.searchIn === 'TV') {
51
- this.locationHandler(formatUrl(`/details/tv?q=${query}`, this.baseHost));
52
- e.preventDefault();
53
- return false;
54
- }
55
-
56
- this.trackSubmit(e);
57
- return true;
58
- }
59
-
60
- toggleSearchMenu() {
61
- if (this.openMenu === 'search') {
62
- return;
63
- }
64
- this.dispatchEvent(new CustomEvent('menuToggled', {
65
- detail: {
66
- menuName: 'search'
67
- },
68
- composed: true,
69
- bubbles: true,
70
- }));
71
- }
72
-
73
- get searchInsideInput() {
74
- return this.searchIn ? html`<input type='hidden' name='sin' value='${this.searchIn}' />` : nothing;
75
- }
76
-
77
- get searchEndpoint() {
78
- return '/search';
79
- }
80
-
81
- render() {
82
- const searchMenuClass = this.open ? 'flex' : 'search-inactive';
83
-
84
- return html`
85
- <div class="search-activated fade-in ${searchMenuClass}">
86
- <form
87
- id="nav-search"
88
- class="highlight"
89
- action=${formatUrl(this.searchEndpoint, this.baseHost)}
90
- method="get"
91
- @submit=${this.search}
92
- data-event-submit-tracking="${this.config.eventCategory}|NavSearchSubmit"
93
- >
94
- <input
95
- type="text"
96
- name="query"
97
- class="search-field"
98
- placeholder="Search"
99
- autocomplete="off"
100
- @focus=${this.toggleSearchMenu}
101
- value=${this.searchQuery || ''}
102
- />
103
- ${this.searchInsideInput}
104
- <button
105
- type="submit"
106
- class="search"
107
- data-event-click-tracking="${this.config.eventCategory}|NavSearchClose"
108
- >
109
- ${icons.search}
110
- </button>
111
- </form>
112
- </div>
113
- `;
114
- }
115
- }
116
-
117
- customElements.define('nav-search', NavSearch);
1
+ import { nothing, html } from 'https://offshoot.prod.archive.org/lit.js';
2
+
3
+ import TrackedElement from './tracked-element.js';
4
+ import navSearchCSS from './styles/nav-search.js';
5
+ import icons from './assets/img/icons.js';
6
+ import formatUrl from './lib/formatUrl.js';
7
+
8
+ class NavSearch extends TrackedElement {
9
+ static get styles() {
10
+ return navSearchCSS;
11
+ }
12
+
13
+ static get properties() {
14
+ return {
15
+ baseHost: { type: String },
16
+ config: { type: Object },
17
+ locationHandler: { type: Object },
18
+ open: { type: Boolean },
19
+ openMenu: { type: String },
20
+ searchIn: { type: String },
21
+ searchQuery: { type: String },
22
+ };
23
+ }
24
+
25
+ constructor() {
26
+ super();
27
+ this.config = {};
28
+ this.locationHandler = () => { };
29
+ this.open = false;
30
+ this.openMenu = '';
31
+ this.searchIn = '';
32
+ }
33
+
34
+ search(e) {
35
+ const query = this.shadowRoot.querySelector('[name=query]').value;
36
+
37
+ if (!query) {
38
+ e.preventDefault();
39
+ return false;
40
+ }
41
+
42
+ // TV search points to a detail page with a q param instead
43
+ if (this.searchIn === 'TV') {
44
+ this.locationHandler(formatUrl(`/details/tv?q=${query}`, this.baseHost));
45
+ e.preventDefault();
46
+ return false;
47
+ }
48
+
49
+ this.trackSubmit(e);
50
+ return true;
51
+ }
52
+
53
+ toggleSearchMenu() {
54
+ if (this.openMenu === 'search') {
55
+ return;
56
+ }
57
+ this.dispatchEvent(new CustomEvent('menuToggled', {
58
+ detail: {
59
+ menuName: 'search'
60
+ },
61
+ composed: true,
62
+ bubbles: true,
63
+ }));
64
+ }
65
+
66
+ get searchInsideInput() {
67
+ return this.searchIn ? html`<input type='hidden' name='sin' value='${this.searchIn}' />` : nothing;
68
+ }
69
+
70
+ get searchEndpoint() {
71
+ return '/search';
72
+ }
73
+
74
+ render() {
75
+ const searchMenuClass = this.open ? 'flex' : 'search-inactive';
76
+
77
+ return html`
78
+ <div class="search-activated fade-in ${searchMenuClass}">
79
+ <form
80
+ id="nav-search"
81
+ class="highlight"
82
+ action=${formatUrl(this.searchEndpoint, this.baseHost)}
83
+ method="get"
84
+ @submit=${this.search}
85
+ data-event-submit-tracking="${this.config.eventCategory}|NavSearchSubmit"
86
+ >
87
+ <input
88
+ type="text"
89
+ name="query"
90
+ class="search-field"
91
+ placeholder="Search"
92
+ autocomplete="off"
93
+ value=${this.searchQuery || ''}
94
+ @focus=${this.toggleSearchMenu}
95
+ />
96
+ ${this.searchInsideInput}
97
+ <button
98
+ type="submit"
99
+ class="search"
100
+ tabindex="-1"
101
+ data-event-click-tracking="${this.config.eventCategory}|NavSearchClose"
102
+ >
103
+ ${icons.search}
104
+ </button>
105
+ </form>
106
+ </div>
107
+ `;
108
+ }
109
+ }
110
+
111
+ customElements.define('nav-search', NavSearch);