From 725e5b9bb958e4d22ffe9d834c2b3f63f7532ada Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 4 Jan 2024 11:06:05 -0700 Subject: [PATCH 01/26] Class Notes node themeing --- boulder_base.libraries.yml | 6 ++++++ css/ucb-class-notes.css | 3 +++ .../content/node--ucb-class-notes.html.twig | 19 +++++++++++++++++++ ...ield--node--field-ucb-class-year.html.twig | 4 ++++ 4 files changed, 32 insertions(+) create mode 100644 css/ucb-class-notes.css create mode 100644 templates/content/node--ucb-class-notes.html.twig create mode 100644 templates/field/field--node--field-ucb-class-year.html.twig diff --git a/boulder_base.libraries.yml b/boulder_base.libraries.yml index 74414d5b..bb9dd79b 100644 --- a/boulder_base.libraries.yml +++ b/boulder_base.libraries.yml @@ -457,3 +457,9 @@ ucb-user-page: theme: css/ucb-status-page-block.css: {} css/ucb-user-page.css: {} + +ucb-class-notes: + version: 1.x + css: + theme: + css/ucb-class-notes.css: {} diff --git a/css/ucb-class-notes.css b/css/ucb-class-notes.css new file mode 100644 index 00000000..33c8fe9c --- /dev/null +++ b/css/ucb-class-notes.css @@ -0,0 +1,3 @@ +.ucb-class-notes{ + padding: 20px 0; +} \ No newline at end of file diff --git a/templates/content/node--ucb-class-notes.html.twig b/templates/content/node--ucb-class-notes.html.twig new file mode 100644 index 00000000..1f2aa0fe --- /dev/null +++ b/templates/content/node--ucb-class-notes.html.twig @@ -0,0 +1,19 @@ +{{ attach_library('boulder_base/ucb-class-notes') }} + +{% set classes = [ + 'node', + 'ucb-class-notes', + 'container', + ] %} + + + + {{ label }} + + {% if content %} + + {{ content }} + + {% endif %} + + \ No newline at end of file diff --git a/templates/field/field--node--field-ucb-class-year.html.twig b/templates/field/field--node--field-ucb-class-year.html.twig new file mode 100644 index 00000000..cb6251dc --- /dev/null +++ b/templates/field/field--node--field-ucb-class-year.html.twig @@ -0,0 +1,4 @@ +{% for item in items %} +

Class Year

+ {{ item.content}} +{% endfor %} \ No newline at end of file From 542d57180878c08f018a52dbc46087aa5b6d118e Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 4 Jan 2024 15:32:56 -0700 Subject: [PATCH 02/26] wip: base files for Class Note List Page --- boulder_base.libraries.yml | 8 +++++ css/ucb-class-notes-list.css | 19 ++++++++++++ js/ucb-class-notes-list.js | 1 + .../node--ucb-class-notes-list-page.html.twig | 31 +++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 css/ucb-class-notes-list.css create mode 100644 js/ucb-class-notes-list.js create mode 100644 templates/content/node--ucb-class-notes-list-page.html.twig diff --git a/boulder_base.libraries.yml b/boulder_base.libraries.yml index bb9dd79b..9e4e2e18 100644 --- a/boulder_base.libraries.yml +++ b/boulder_base.libraries.yml @@ -463,3 +463,11 @@ ucb-class-notes: css: theme: css/ucb-class-notes.css: {} + +ucb-class-notes-list-page: + version: 1.x + js: + js/ucb-class-notes-list.js: {} + css: + theme: + css/ucb-class-notes-list.css: {} diff --git a/css/ucb-class-notes-list.css b/css/ucb-class-notes-list.css new file mode 100644 index 00000000..5e30b02b --- /dev/null +++ b/css/ucb-class-notes-list.css @@ -0,0 +1,19 @@ +.ucb-list-msg { + font-size: 1.25em; + font-weight: bolder; + text-align: center; + } + + .ucb-loading-data { + color: #01579b; + text-align: center; + } + + .ucb-list-msg, + .ucb-loading-data { + display: block; + } + .ucb-list-msg[hidden], + .ucb-loading-data[hidden] { + display: none; + } \ No newline at end of file diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js new file mode 100644 index 00000000..123c9237 --- /dev/null +++ b/js/ucb-class-notes-list.js @@ -0,0 +1 @@ +console.log("Attached") \ No newline at end of file diff --git a/templates/content/node--ucb-class-notes-list-page.html.twig b/templates/content/node--ucb-class-notes-list-page.html.twig new file mode 100644 index 00000000..348be61c --- /dev/null +++ b/templates/content/node--ucb-class-notes-list-page.html.twig @@ -0,0 +1,31 @@ + +{{ attach_library('boulder_base/ucb-class-notes-list-page') }} + +{% set classes = [ + 'node', + 'container', + 'node--type-' ~ node.bundle|clean_class, + node.isPromoted() ? 'node--promoted', + node.isSticky() ? 'node--sticky', + not node.isPublished() ? 'node--unpublished', + view_mode ? 'node--view-mode-' ~ view_mode|clean_class, + 'ucb-content-wrapper' + ] %} + + +
+ + {{ label }} + +
+ {% if content.body|render %} +
+ {{ content.body }} +
+ {% endif %} + ')|render|trim('/') ~ '/jsonapi', +})}}> + + + From 314ac7aae14a8145eb2aecfe600773f783976151 Mon Sep 17 00:00:00 2001 From: Pat Date: Fri, 5 Jan 2024 10:57:29 -0700 Subject: [PATCH 03/26] wip: setting up custom web component --- js/ucb-class-notes-list.js | 32 ++++++++++++++++++- .../node--ucb-class-notes-list-page.html.twig | 2 +- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 123c9237..bc4f598b 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -1 +1,31 @@ -console.log("Attached") \ No newline at end of file +console.log("Attached") + +class ClassNotesListElement extends HTMLElement { + + constructor() { + super(); + const JSONURL = this.getAttribute('base-uri'); + console.log(JSONURL) + } + + build() { + } + + toggleMessageDisplay(element, display, className, innerText) { + if(className) + element.className = className; + if(innerText) + element.innerText = innerText; + if(display === 'none') + element.setAttribute('hidden', ''); + else element.removeAttribute('hidden'); + } + + generateForm(){ + } + + generateDropdown(){ + } +} + +customElements.define('ucb-class-notes-list', ClassNotesListElement); diff --git a/templates/content/node--ucb-class-notes-list-page.html.twig b/templates/content/node--ucb-class-notes-list-page.html.twig index 348be61c..126e9e78 100644 --- a/templates/content/node--ucb-class-notes-list-page.html.twig +++ b/templates/content/node--ucb-class-notes-list-page.html.twig @@ -27,5 +27,5 @@ 'base-uri': url('')|render|trim('/') ~ '/jsonapi', })}}> - + From 43727aca9da413fe8b700df0251f72355a38bc61 Mon Sep 17 00:00:00 2001 From: Pat Date: Mon, 8 Jan 2024 14:35:00 -0700 Subject: [PATCH 04/26] wip: adds date array, json url --- js/ucb-class-notes-list.js | 63 ++++++++++++++++++- .../node--ucb-class-notes-list-page.html.twig | 13 +++- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index bc4f598b..8b6fe4d6 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -4,11 +4,20 @@ class ClassNotesListElement extends HTMLElement { constructor() { super(); + const dates = [1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050] const JSONURL = this.getAttribute('base-uri'); + // Build user filters + // Insert year filter, make call + const year = "" + // TO DO -- need to add year here console.log(JSONURL) + this.build(JSONURL, year ) } - - build() { +// Gets info + build(JSONURL, year) { + console.log("url", JSONURL) + console.log('year', year) + const publishFilter = '&filter[status]=1' } toggleMessageDisplay(element, display, className, innerText) { @@ -21,7 +30,55 @@ class ClassNotesListElement extends HTMLElement { else element.removeAttribute('hidden'); } - generateForm(){ + generateForm(){ + // Create Elements + const form = document.createElement('form'), + formDiv = document.createElement('div'); + form.className = 'class-notes-list-filter'; + formDiv.className = 'd-flex align-items-center'; + + // If User-Filterable...Create Dropdowns + for(const key in ){ + const filter = userAccessibleFilters[key]; + // Create container + const container = document.createElement('div'); + container.className = `form-item-${key} form-item`; + // Create label el + const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); + itemLabelSpan.innerText = filter['label']; + itemLabel.appendChild(itemLabelSpan); + // Create select el + const selectFilter = document.createElement('select'); + selectFilter.name = key; + selectFilter.className = 'taxonomy-select-' + key + ' taxonomy-select'; + selectFilter.onchange = event => onChange(event.target.form); + + if(filter['includes'].length != 1) { + // All option as first entry + const defaultOption = document.createElement('option'); + defaultOption.value = '-1'; + defaultOption.innerText = 'All'; + defaultOption.className = 'taxonomy-option-all taxonomy-option-default'; + if(!filter['restrict'] && filter['includes'].length > 1){ + defaultOption.innerText = 'Default'; + defaultOption.className = 'taxonomy-option-default'; + const allOptions = document.createElement('option'); + allOptions.innerText = 'All'; + allOptions.value = ''; + allOptions.className = 'taxonomy-option-all'; + selectFilter.appendChild(allOptions); + } + defaultOption.selected = true; + // Append + selectFilter.appendChild(defaultOption); + } + itemLabel.appendChild(selectFilter); + container.appendChild(itemLabel); + formDiv.appendChild(container); + } + + form.appendChild(formDiv); + this._userFormElement.appendChild(form); } generateDropdown(){ diff --git a/templates/content/node--ucb-class-notes-list-page.html.twig b/templates/content/node--ucb-class-notes-list-page.html.twig index 126e9e78..adc7c454 100644 --- a/templates/content/node--ucb-class-notes-list-page.html.twig +++ b/templates/content/node--ucb-class-notes-list-page.html.twig @@ -1,4 +1,7 @@ - +{# + + http://localhost:50282/jsonapi/node/ucb_class_notes + #} {{ attach_library('boulder_base/ucb-class-notes-list-page') }} {% set classes = [ @@ -11,6 +14,12 @@ view_mode ? 'node--view-mode-' ~ view_mode|clean_class, 'ucb-content-wrapper' ] %} + + + {% set PublishedFilter = '&filter[publish-check][condition][path]=status' + ~ '&filter[publish-check][condition][value]=1' + ~ '&filter[publish-check][condition][memberOf]=published' +%}
@@ -24,7 +33,7 @@
{% endif %} ')|render|trim('/') ~ '/jsonapi', + 'base-uri': url('')|render|trim('/') ~ '/jsonapi/node/ucb_class_notes?filter[field_ucb_class_year]=', })}}> From 7b16db0b2e52e0e2dd723343b30ed97eccd7e0d0 Mon Sep 17 00:00:00 2001 From: Pat Date: Tue, 9 Jan 2024 16:47:40 -0700 Subject: [PATCH 05/26] Adds handleError, gets data response --- js/ucb-class-notes-list.js | 105 ++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 8b6fe4d6..3e5f8ac0 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -8,16 +8,29 @@ class ClassNotesListElement extends HTMLElement { const JSONURL = this.getAttribute('base-uri'); // Build user filters // Insert year filter, make call - const year = "" + const year = "1901" // TO DO -- need to add year here console.log(JSONURL) - this.build(JSONURL, year ) + this.getData(JSONURL, year) } // Gets info - build(JSONURL, year) { - console.log("url", JSONURL) - console.log('year', year) + getData(JSONURL, year) { const publishFilter = '&filter[status]=1' + const API = JSONURL + year + publishFilter + fetch(API) + .then(this.handleError) + .then((data) => {console.log(data)}) + .catch(Error=> { + console.error('There was an error fetching data from the API - Please try again later.') + console.error(Error) + this.toggleMessage('ucb-al-loading') + this.toggleMessage('ucb-al-api-error', "block") + }); + } + + build(data){ + console.log(data) + } toggleMessageDisplay(element, display, className, innerText) { @@ -38,44 +51,44 @@ class ClassNotesListElement extends HTMLElement { formDiv.className = 'd-flex align-items-center'; // If User-Filterable...Create Dropdowns - for(const key in ){ - const filter = userAccessibleFilters[key]; - // Create container - const container = document.createElement('div'); - container.className = `form-item-${key} form-item`; - // Create label el - const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); - itemLabelSpan.innerText = filter['label']; - itemLabel.appendChild(itemLabelSpan); - // Create select el - const selectFilter = document.createElement('select'); - selectFilter.name = key; - selectFilter.className = 'taxonomy-select-' + key + ' taxonomy-select'; - selectFilter.onchange = event => onChange(event.target.form); + // for(const key in ){ + // const filter = userAccessibleFilters[key]; + // // Create container + // const container = document.createElement('div'); + // container.className = `form-item-${key} form-item`; + // // Create label el + // const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); + // itemLabelSpan.innerText = filter['label']; + // itemLabel.appendChild(itemLabelSpan); + // // Create select el + // const selectFilter = document.createElement('select'); + // selectFilter.name = key; + // selectFilter.className = 'taxonomy-select-' + key + ' taxonomy-select'; + // selectFilter.onchange = event => onChange(event.target.form); - if(filter['includes'].length != 1) { - // All option as first entry - const defaultOption = document.createElement('option'); - defaultOption.value = '-1'; - defaultOption.innerText = 'All'; - defaultOption.className = 'taxonomy-option-all taxonomy-option-default'; - if(!filter['restrict'] && filter['includes'].length > 1){ - defaultOption.innerText = 'Default'; - defaultOption.className = 'taxonomy-option-default'; - const allOptions = document.createElement('option'); - allOptions.innerText = 'All'; - allOptions.value = ''; - allOptions.className = 'taxonomy-option-all'; - selectFilter.appendChild(allOptions); - } - defaultOption.selected = true; - // Append - selectFilter.appendChild(defaultOption); - } - itemLabel.appendChild(selectFilter); - container.appendChild(itemLabel); - formDiv.appendChild(container); - } + // if(filter['includes'].length != 1) { + // // All option as first entry + // const defaultOption = document.createElement('option'); + // defaultOption.value = '-1'; + // defaultOption.innerText = 'All'; + // defaultOption.className = 'taxonomy-option-all taxonomy-option-default'; + // if(!filter['restrict'] && filter['includes'].length > 1){ + // defaultOption.innerText = 'Default'; + // defaultOption.className = 'taxonomy-option-default'; + // const allOptions = document.createElement('option'); + // allOptions.innerText = 'All'; + // allOptions.value = ''; + // allOptions.className = 'taxonomy-option-all'; + // selectFilter.appendChild(allOptions); + // } + // defaultOption.selected = true; + // // Append + // selectFilter.appendChild(defaultOption); + // } + // itemLabel.appendChild(selectFilter); + // container.appendChild(itemLabel); + // formDiv.appendChild(container); + // } form.appendChild(formDiv); this._userFormElement.appendChild(form); @@ -83,6 +96,14 @@ class ClassNotesListElement extends HTMLElement { generateDropdown(){ } + + handleError = response => { + if (!response.ok) { + throw new Error; + } else { + return response.json(); + } + }; } customElements.define('ucb-class-notes-list', ClassNotesListElement); From 3b2ef582a8922925d6dfca48af41a3de3312af05 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 10 Jan 2024 11:45:39 -0700 Subject: [PATCH 06/26] wip: Dropdown triggers API calls --- js/ucb-class-notes-list.js | 83 +++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 3e5f8ac0..8ef7fd44 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -1,20 +1,23 @@ -console.log("Attached") - class ClassNotesListElement extends HTMLElement { - constructor() { super(); + const + chromeElement = this._chromeElement = document.createElement('div'), + userFormElement = this._userFormElement = document.createElement('div'); + chromeElement.appendChild(userFormElement); + this.appendChild(chromeElement); const dates = [1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050] const JSONURL = this.getAttribute('base-uri'); // Build user filters + this.generateForm(dates) // Insert year filter, make call const year = "1901" - // TO DO -- need to add year here + // TO DO -- need to add year here -- make function console.log(JSONURL) this.getData(JSONURL, year) } // Gets info - getData(JSONURL, year) { + getData(JSONURL, year, data = []) { const publishFilter = '&filter[status]=1' const API = JSONURL + year + publishFilter fetch(API) @@ -27,12 +30,9 @@ class ClassNotesListElement extends HTMLElement { this.toggleMessage('ucb-al-api-error', "block") }); } - build(data){ console.log(data) - } - toggleMessageDisplay(element, display, className, innerText) { if(className) element.className = className; @@ -43,7 +43,7 @@ class ClassNotesListElement extends HTMLElement { else element.removeAttribute('hidden'); } - generateForm(){ + generateForm(dates){ // Create Elements const form = document.createElement('form'), formDiv = document.createElement('div'); @@ -51,52 +51,45 @@ class ClassNotesListElement extends HTMLElement { formDiv.className = 'd-flex align-items-center'; // If User-Filterable...Create Dropdowns - // for(const key in ){ - // const filter = userAccessibleFilters[key]; // // Create container - // const container = document.createElement('div'); - // container.className = `form-item-${key} form-item`; + const container = document.createElement('div'); + container.className = `form-item`; // // Create label el - // const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); - // itemLabelSpan.innerText = filter['label']; - // itemLabel.appendChild(itemLabelSpan); + const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); + // itemLabelSpan.innerText = filter['label']; + itemLabel.appendChild(itemLabelSpan); // // Create select el - // const selectFilter = document.createElement('select'); - // selectFilter.name = key; - // selectFilter.className = 'taxonomy-select-' + key + ' taxonomy-select'; - // selectFilter.onchange = event => onChange(event.target.form); - - // if(filter['includes'].length != 1) { - // // All option as first entry - // const defaultOption = document.createElement('option'); - // defaultOption.value = '-1'; - // defaultOption.innerText = 'All'; - // defaultOption.className = 'taxonomy-option-all taxonomy-option-default'; - // if(!filter['restrict'] && filter['includes'].length > 1){ - // defaultOption.innerText = 'Default'; - // defaultOption.className = 'taxonomy-option-default'; - // const allOptions = document.createElement('option'); - // allOptions.innerText = 'All'; - // allOptions.value = ''; - // allOptions.className = 'taxonomy-option-all'; - // selectFilter.appendChild(allOptions); - // } - // defaultOption.selected = true; - // // Append - // selectFilter.appendChild(defaultOption); - // } - // itemLabel.appendChild(selectFilter); - // container.appendChild(itemLabel); - // formDiv.appendChild(container); - // } + const selectFilter = document.createElement('select'); + selectFilter.name = "Year" + selectFilter.className = 'Year Select'; + selectFilter.onchange = this.onYearChange.bind(this); // Bind the event handler + itemLabel.appendChild(selectFilter); + container.appendChild(itemLabel); + formDiv.appendChild(container); + this.generateDropdown(dates, selectFilter) form.appendChild(formDiv); + console.log("what is this", this._userFormElement) this._userFormElement.appendChild(form); } - generateDropdown(){ + generateDropdown(dates, selectElement){ + console.log("dates", dates) + dates.map(date => { + const option = document.createElement('option'); + option.value = date; + option.innerText = date; + selectElement.appendChild(option); + }) } + // Event handler for the dropdown change + onYearChange(event) { + const year = event.target.value; + const JSONURL = this.getAttribute('base-uri'); + this.getData(JSONURL, year); + } + handleError = response => { if (!response.ok) { throw new Error; From 7789b684f36721e063ac5be084c0512cdf8d253e Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 10 Jan 2024 13:54:06 -0700 Subject: [PATCH 07/26] wip: adds sort by form elements --- js/ucb-class-notes-list.js | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 8ef7fd44..dc88d19a 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -12,8 +12,6 @@ class ClassNotesListElement extends HTMLElement { this.generateForm(dates) // Insert year filter, make call const year = "1901" - // TO DO -- need to add year here -- make function - console.log(JSONURL) this.getData(JSONURL, year) } // Gets info @@ -22,7 +20,7 @@ class ClassNotesListElement extends HTMLElement { const API = JSONURL + year + publishFilter fetch(API) .then(this.handleError) - .then((data) => {console.log(data)}) + .then((data) => this.build(data)) .catch(Error=> { console.error('There was an error fetching data from the API - Please try again later.') console.error(Error) @@ -49,16 +47,14 @@ class ClassNotesListElement extends HTMLElement { formDiv = document.createElement('div'); form.className = 'class-notes-list-filter'; formDiv.className = 'd-flex align-items-center'; - - // If User-Filterable...Create Dropdowns - // // Create container + // Create container const container = document.createElement('div'); container.className = `form-item`; - // // Create label el + // Create label el const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); - // itemLabelSpan.innerText = filter['label']; + itemLabelSpan.innerText = "Filter by Year:"; itemLabel.appendChild(itemLabelSpan); - // // Create select el + // Create select el const selectFilter = document.createElement('select'); selectFilter.name = "Year" selectFilter.className = 'Year Select'; @@ -66,15 +62,29 @@ class ClassNotesListElement extends HTMLElement { itemLabel.appendChild(selectFilter); container.appendChild(itemLabel); formDiv.appendChild(container); - + // Appends this.generateDropdown(dates, selectFilter) form.appendChild(formDiv); - console.log("what is this", this._userFormElement) this._userFormElement.appendChild(form); + + // Sort By : Create container + const sortContainer = document.createElement('div'); + sortContainer.classList.add('form-item', "sort-form-item"); + // Create label el + const sortItemLabel = document.createElement('label'), sortItemLabelSpan = document.createElement('span'); + sortItemLabelSpan.innerText = "Sort By:"; + sortItemLabel.appendChild(sortItemLabelSpan); + const sortSelectFilter = document.createElement('select'); + sortSelectFilter.name = "Sort" + sortSelectFilter.className = 'Sort Select'; + sortSelectFilter.onchange = this.onYearChange.bind(this); // Bind the event handler + sortItemLabel.appendChild(sortSelectFilter); + container.appendChild(sortItemLabel); + formDiv.appendChild(container); + this.generateDropdown(["Class Year", "Date Posted"],sortSelectFilter) } generateDropdown(dates, selectElement){ - console.log("dates", dates) dates.map(date => { const option = document.createElement('option'); option.value = date; From 0fad1bc38a7cbb08a77a2c9ba1a88fb1f3322b9d Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 10 Jan 2024 14:53:48 -0700 Subject: [PATCH 08/26] wip: View all notes --- js/ucb-class-notes-list.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index dc88d19a..708a51f8 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -28,6 +28,7 @@ class ClassNotesListElement extends HTMLElement { this.toggleMessage('ucb-al-api-error', "block") }); } + // TO DO : construct build(data){ console.log(data) } @@ -51,7 +52,8 @@ class ClassNotesListElement extends HTMLElement { const container = document.createElement('div'); container.className = `form-item`; // Create label el - const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); + const itemLabel = document.createElement('label'), + itemLabelSpan = document.createElement('span'); itemLabelSpan.innerText = "Filter by Year:"; itemLabel.appendChild(itemLabelSpan); // Create select el @@ -82,6 +84,15 @@ class ClassNotesListElement extends HTMLElement { container.appendChild(sortItemLabel); formDiv.appendChild(container); this.generateDropdown(["Class Year", "Date Posted"],sortSelectFilter) + + + // Add 'View All Notes' Link + const viewAllLink = document.createElement('a'); + viewAllLink.href = '#'; + viewAllLink.innerText = 'View All Notes'; + viewAllLink.addEventListener('click', this.viewAllNotes.bind(this)); + form.appendChild(viewAllLink); + this._userFormElement.appendChild(form); } generateDropdown(dates, selectElement){ @@ -100,6 +111,12 @@ class ClassNotesListElement extends HTMLElement { this.getData(JSONURL, year); } + // Event handler for View All -- no year specified + viewAllNotes(event){ + event.preventDefault(); + console.log('View all notes pressed') + } + handleError = response => { if (!response.ok) { throw new Error; From 3a6def162dbc40bceaf692caaab9f250da3043c6 Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 11 Jan 2024 10:58:13 -0700 Subject: [PATCH 09/26] wip: iterates through all notes, adjusts filters --- js/ucb-class-notes-list.js | 33 +++++++++++++++---- .../node--ucb-class-notes-list-page.html.twig | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 708a51f8..42344b27 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -11,16 +11,37 @@ class ClassNotesListElement extends HTMLElement { // Build user filters this.generateForm(dates) // Insert year filter, make call - const year = "1901" - this.getData(JSONURL, year) + this.getData(JSONURL, "") } // Gets info - getData(JSONURL, year, data = []) { - const publishFilter = '&filter[status]=1' - const API = JSONURL + year + publishFilter + getData(JSONURL, year = '', notes = [], next = false) { + let yearFilter = ''; + let publishFilter = '' + // If its not a next link, build the JSON API URL + if(!next){ + if (year) { + yearFilter = `?filter[field_ucb_class_year]=${year}` + publishFilter = '&filter[status]=1' + } else { + yearFilter = '' + publishFilter = '?filter[status]=1' + } + } + const API = JSONURL + yearFilter + publishFilter fetch(API) .then(this.handleError) - .then((data) => this.build(data)) + .then((data) => { + if (data.links.next){ + data.data.forEach(note=>{ + notes.push(note) + }) + this.getData(data.links.next.href,'',notes,true) + } + + if(!data.links.next){ + this.build(notes) + } + }) .catch(Error=> { console.error('There was an error fetching data from the API - Please try again later.') console.error(Error) diff --git a/templates/content/node--ucb-class-notes-list-page.html.twig b/templates/content/node--ucb-class-notes-list-page.html.twig index adc7c454..67725351 100644 --- a/templates/content/node--ucb-class-notes-list-page.html.twig +++ b/templates/content/node--ucb-class-notes-list-page.html.twig @@ -33,7 +33,7 @@ {% endif %} ')|render|trim('/') ~ '/jsonapi/node/ucb_class_notes?filter[field_ucb_class_year]=', + 'base-uri': url('')|render|trim('/') ~ '/jsonapi/node/ucb_class_notes', })}}> From 4678700ce445bb540ecb9aabf3414d266ee6975a Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 11 Jan 2024 11:19:15 -0700 Subject: [PATCH 10/26] wip: style pass for filters, adding logic for all years --- css/ucb-class-notes-list.css | 17 ++++++++++++++++- js/ucb-class-notes-list.js | 8 +++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/css/ucb-class-notes-list.css b/css/ucb-class-notes-list.css index 5e30b02b..6ba7c2ef 100644 --- a/css/ucb-class-notes-list.css +++ b/css/ucb-class-notes-list.css @@ -16,4 +16,19 @@ .ucb-list-msg[hidden], .ucb-loading-data[hidden] { display: none; - } \ No newline at end of file + } + +.class-notes-list-filter{ + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + padding: 10px; + border: 1px solid rgba(128, 128, 128, 0.333); + min-width: auto; +} + +.ucb-class-notes-filter-label{ + font-size: 85%; + font-weight: 600; +} \ No newline at end of file diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 42344b27..c157bcd0 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -6,7 +6,7 @@ class ClassNotesListElement extends HTMLElement { userFormElement = this._userFormElement = document.createElement('div'); chromeElement.appendChild(userFormElement); this.appendChild(chromeElement); - const dates = [1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050] + const dates = ['--Select date--', 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050] const JSONURL = this.getAttribute('base-uri'); // Build user filters this.generateForm(dates) @@ -75,6 +75,7 @@ class ClassNotesListElement extends HTMLElement { // Create label el const itemLabel = document.createElement('label'), itemLabelSpan = document.createElement('span'); + itemLabelSpan.classList.add('filter-by-label','ucb-class-notes-filter-label') itemLabelSpan.innerText = "Filter by Year:"; itemLabel.appendChild(itemLabelSpan); // Create select el @@ -96,6 +97,7 @@ class ClassNotesListElement extends HTMLElement { // Create label el const sortItemLabel = document.createElement('label'), sortItemLabelSpan = document.createElement('span'); sortItemLabelSpan.innerText = "Sort By:"; + sortItemLabelSpan.classList.add('sort-by-label','ucb-class-notes-filter-label') sortItemLabel.appendChild(sortItemLabelSpan); const sortSelectFilter = document.createElement('select'); sortSelectFilter.name = "Sort" @@ -119,7 +121,11 @@ class ClassNotesListElement extends HTMLElement { generateDropdown(dates, selectElement){ dates.map(date => { const option = document.createElement('option'); + if(date === '--Select date--'){ + option.value = '' + } else { option.value = date; + } option.innerText = date; selectElement.appendChild(option); }) From 4cf27bcc2a3599f0302aab3ab81efeaf92a124b0 Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 11 Jan 2024 14:07:36 -0700 Subject: [PATCH 11/26] wip: rendering data, needs loader button, spinner, sort functionality wired --- css/ucb-class-notes-list.css | 6 +++ js/ucb-class-notes-list.js | 76 ++++++++++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/css/ucb-class-notes-list.css b/css/ucb-class-notes-list.css index 6ba7c2ef..9edef803 100644 --- a/css/ucb-class-notes-list.css +++ b/css/ucb-class-notes-list.css @@ -31,4 +31,10 @@ .ucb-class-notes-filter-label{ font-size: 85%; font-weight: 600; +} + +.ucb-class-notes-view-all-container{ + flex: 1; + text-align: right; + font-size: 85%; } \ No newline at end of file diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index c157bcd0..95cfd307 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -39,7 +39,7 @@ class ClassNotesListElement extends HTMLElement { } if(!data.links.next){ - this.build(notes) + this.build(notes, year) } }) .catch(Error=> { @@ -50,8 +50,37 @@ class ClassNotesListElement extends HTMLElement { }); } // TO DO : construct - build(data){ - console.log(data) + build(data, year){ + // Build container + const classNotesContainer = document.createElement('div') + classNotesContainer.classList.add('ucb-class-notes-list-container') + // Build Notes + data.forEach(note => { + const classNote = document.createElement('article') + classNote.classList.add('ucb-class-notes-list-note-item') + // Date + if(!year){ + const classNoteYearContainer = document.createElement('div') + classNoteYearContainer.classList.add('class-note-year') + const classNoteYearLink = document.createElement('a') + classNoteYearLink.href = '#'; + classNoteYearLink.innerText = note.attributes.field_ucb_class_year; + classNoteYearLink.addEventListener('click', this.onYearSelect.bind(this)); + classNoteYearContainer.appendChild(classNoteYearLink) + classNote.appendChild(classNoteYearContainer) + } + // Class Note Text + const classNoteParagraph = document.createElement('p') + classNoteParagraph.innerHTML = this.escapeHTML(note.attributes.body.processed) + classNote.appendChild(classNoteParagraph) + // Date posted + const classNotePosted = document.createElement('p') + classNotePosted.classList.add('class-note-posted-date') + classNotePosted.innerText = `Posted ${this.formatDateString(note.attributes.created)}` + classNote.appendChild(classNotePosted) + classNotesContainer.appendChild(classNote) + }) + this.appendChild(classNotesContainer) } toggleMessageDisplay(element, display, className, innerText) { if(className) @@ -102,7 +131,7 @@ class ClassNotesListElement extends HTMLElement { const sortSelectFilter = document.createElement('select'); sortSelectFilter.name = "Sort" sortSelectFilter.className = 'Sort Select'; - sortSelectFilter.onchange = this.onYearChange.bind(this); // Bind the event handler + sortSelectFilter.onchange = this.onSortChange.bind(this); // Bind the event handler sortItemLabel.appendChild(sortSelectFilter); container.appendChild(sortItemLabel); formDiv.appendChild(container); @@ -110,11 +139,14 @@ class ClassNotesListElement extends HTMLElement { // Add 'View All Notes' Link + const viewAllLinkContainer = document.createElement('div') + viewAllLinkContainer.classList.add('ucb-class-notes-view-all-container') const viewAllLink = document.createElement('a'); viewAllLink.href = '#'; viewAllLink.innerText = 'View All Notes'; viewAllLink.addEventListener('click', this.viewAllNotes.bind(this)); - form.appendChild(viewAllLink); + viewAllLinkContainer.appendChild(viewAllLink) + form.appendChild(viewAllLinkContainer); this._userFormElement.appendChild(form); } @@ -134,16 +166,46 @@ class ClassNotesListElement extends HTMLElement { // Event handler for the dropdown change onYearChange(event) { const year = event.target.value; - const JSONURL = this.getAttribute('base-uri'); - this.getData(JSONURL, year); + const JSONURL = this.getAttribute('base-uri'); + this.getData(JSONURL, year); } + onYearSelect(year){ + const JSONURL = this.getAttribute('base-uri') + this.getData(JSONURL, year) + } + + onSortChange(event){ + const sort = event.target.value + console.log(sort) + } // Event handler for View All -- no year specified viewAllNotes(event){ event.preventDefault(); console.log('View all notes pressed') } + escapeHTML(raw) { + if (!raw) return ''; + + // First, escape all HTML to prevent execution of unwanted tags or JavaScript. + let escapedHTML = raw.replace(/\&/g, '&').replace(/"/g, '"') + .replace(//g, '>'); + + // Unescape the allowed tags (p, strong, em) + escapedHTML = escapedHTML.replace(/<(\/?p)>/g, '<$1>') + .replace(/<(\/?strong)>/g, '<$1>') + .replace(/<(\/?em)>/g, '<$1>'); + + return escapedHTML; + } + + formatDateString(dateString) { + const options = { year: 'numeric', month: 'short', day: 'numeric' }; + const date = new Date(dateString); + return date.toLocaleDateString('en-US', options); + } + handleError = response => { if (!response.ok) { throw new Error; From f5568f93711e8c88c032b363fb292ca0bdcb9f1b Mon Sep 17 00:00:00 2001 From: Timur Tripp Date: Tue, 16 Jan 2024 16:38:17 -0700 Subject: [PATCH 12/26] CuBoulder/tiamat-theme#616 adds alt text to images in article list --- js/ucb-article-list.js | 401 +++++++++++++++++++++-------------------- 1 file changed, 202 insertions(+), 199 deletions(-) diff --git a/js/ucb-article-list.js b/js/ucb-article-list.js index 558c9282..5a98e4ba 100644 --- a/js/ucb-article-list.js +++ b/js/ucb-article-list.js @@ -1,15 +1,15 @@ /** * Get additional data from the paragraph content attached to the Article node * @param {string} id - internal id used by Drupal to get the specific paragraph - */ + */ async function getArticleParagraph(id) { - if(id) { + if (id) { const response = await fetch( `/jsonapi/paragraph/article_content/${id}` ); return response; } else { - return ""; + return ""; } } @@ -49,173 +49,175 @@ function toggleMessage(id, display = "none") { * @param {string} ExcludeTags - array of tags to filter out when rendering * @returns - Promise with resolve or reject */ -function renderArticleList( JSONURL, ExcludeCategories = "", ExcludeTags = "") { - return new Promise(function(resolve, reject) { - let excludeCatArray = ExcludeCategories.split(",").map(Number); - let excludeTagArray = ExcludeTags.split(",").map(Number); - // next URL if there is one, will be returned by this funtion - let NEXTJSONURL = ""; - - if (JSONURL) { - //let el = document.getElementById(id); - - // show the loading spinner while we load the data - toggleMessage("ucb-al-loading", "block"); - - fetch(JSONURL) - .then((reponse) => reponse.json()) - .then((data) => { - // get the next URL and return that if there is one - if(data.links.next) { - let nextURL = data.links.next.href.split("/jsonapi/"); - NEXTJSONURL = nextURL[1]; - } else { - NEXTJSONURL = ""; - } +function renderArticleList(JSONURL, ExcludeCategories = "", ExcludeTags = "") { + return new Promise(function (resolve, reject) { + let excludeCatArray = ExcludeCategories.split(",").map(Number); + let excludeTagArray = ExcludeTags.split(",").map(Number); + // next URL if there is one, will be returned by this funtion + let NEXTJSONURL = ""; + + if (JSONURL) { + //let el = document.getElementById(id); + + // show the loading spinner while we load the data + toggleMessage("ucb-al-loading", "block"); + + fetch(JSONURL) + .then((reponse) => reponse.json()) + .then((data) => { + // get the next URL and return that if there is one + if (data.links.next) { + let nextURL = data.links.next.href.split("/jsonapi/"); + NEXTJSONURL = nextURL[1]; + } else { + NEXTJSONURL = ""; + } - //console.log("data obj", data); + //console.log("data obj", data); - // if no articles of returned, stop the loading spinner and let the user know we received no data that matches their query - if (!data.data.length) { - toggleMessage("ucb-al-loading", "none"); - toggleMessage("ucb-al-no-results", "block"); - reject; - } + // if no articles of returned, stop the loading spinner and let the user know we received no data that matches their query + if (!data.data.length) { + toggleMessage("ucb-al-loading", "none"); + toggleMessage("ucb-al-no-results", "block"); + reject; + } - // Below objects are needed to match images with their corresponding articles. There are two endpoints => data.data (article) and data.included (incl. media), both needed to associate a media library image with its respective article - let urlObj = {}; - let idObj = {}; - let altObj = {}; - // Remove any blanks from our articles before map - if (data.included) { - // removes all other included data besides images in our included media - let idFilterData = data.included.filter((item) => { - return item.type == "media--image"; - }) + // Below objects are needed to match images with their corresponding articles. There are two endpoints => data.data (article) and data.included (incl. media), both needed to associate a media library image with its respective article + let urlObj = {}; + let idObj = {}; + let altObj = {}; + // Remove any blanks from our articles before map + if (data.included) { + // removes all other included data besides images in our included media + let idFilterData = data.included.filter((item) => { + return item.type == "media--image"; + }) + + let altFilterData = data.included.filter((item) => { + return item.type == 'file--file'; + }); + // finds the focial point version of the thumbnail + altFilterData.map((item) => { + // checks if consumer is working, else default to standard image instead of focal image + if (item.links.focal_image_square != undefined) { + altObj[item.id] = { src: item.links.focal_image_square.href } + } else { + altObj[item.id] = { src: item.attributes.uri.url } + } + }) + + // using the image-only data, creates the idObj => key: thumbnail id, value : data id + idFilterData.map((pair) => { + const thumbnailId = pair.relationships.thumbnail.data.id; + idObj[pair.id] = pair.relationships.thumbnail.data.id; + altObj[thumbnailId].alt = pair.relationships.thumbnail.data.meta.alt; + }) + } + // console.log("idObj", idObj); + // console.log("urlObj", urlObj); + // console.log('altObj', altObj) + //iterate over each item in the array + data.data.map((item) => { + let thisArticleCats = []; + let thisArticleTags = []; + // // loop through and grab all of the categories + if (item.relationships.field_ucb_article_categories) { + for (let i = 0; i < item.relationships.field_ucb_article_categories.data.length; i++) { + thisArticleCats.push( + item.relationships.field_ucb_article_categories.data[i].meta + .drupal_internal__target_id + ) + } + } + // console.log("this article cats",thisArticleCats) - let altFilterData = data.included.filter((item) => { - return item.type == 'file--file'; - }); - // finds the focial point version of the thumbnail - altFilterData.map((item)=>{ - // checks if consumer is working, else default to standard image instead of focal image - if(item.links.focal_image_square != undefined){ - altObj[item.id] = item.links.focal_image_square.href - } else { - altObj[item.id] = item.attributes.uri.url + // // loop through and grab all of the tags + if (item.relationships.field_ucb_article_tags) { + for (var i = 0; i < item.relationships.field_ucb_article_tags.data.length; i++) { + thisArticleTags.push(item.relationships.field_ucb_article_tags.data[i].meta.drupal_internal__target_id) + } } - }) + // console.log('this article tags',thisArticleTags) - // using the image-only data, creates the idObj => key: thumbnail id, value : data id - idFilterData.map((pair) => { - idObj[pair.id] = pair.relationships.thumbnail.data.id; - }) - } - // console.log("idObj", idObj); - // console.log("urlObj", urlObj); - // console.log('altObj', altObj) - //iterate over each item in the array - data.data.map((item) => { - let thisArticleCats = []; - let thisArticleTags = []; - // // loop through and grab all of the categories - if (item.relationships.field_ucb_article_categories) { - for (let i = 0; i < item.relationships.field_ucb_article_categories.data.length; i++) { - thisArticleCats.push( - item.relationships.field_ucb_article_categories.data[i].meta - .drupal_internal__target_id + // checks to see if the current article (item) contains a category or tag scheduled for exclusion + let doesIncludeCat = thisArticleCats; + let doesIncludeTag = thisArticleTags; + + // check to see if we need to filter on categories + if (excludeCatArray.length && thisArticleCats.length) { + doesIncludeCat = thisArticleCats.filter((element) => + excludeCatArray.includes(element) ) } - } - // console.log("this article cats",thisArticleCats) - - // // loop through and grab all of the tags - if (item.relationships.field_ucb_article_tags) { - for (var i = 0; i < item.relationships.field_ucb_article_tags.data.length; i++) { - thisArticleTags.push(item.relationships.field_ucb_article_tags.data[i].meta.drupal_internal__target_id) + // check to see if we need to filter on tags + if (excludeTagArray.length && thisArticleTags.length) { + doesIncludeTag = thisArticleTags.filter((element) => + excludeTagArray.includes(element) + ) } - } - // console.log('this article tags',thisArticleTags) - // checks to see if the current article (item) contains a category or tag scheduled for exclusion - let doesIncludeCat = thisArticleCats; - let doesIncludeTag = thisArticleTags; - - // check to see if we need to filter on categories - if (excludeCatArray.length && thisArticleCats.length) { - doesIncludeCat = thisArticleCats.filter((element) => - excludeCatArray.includes(element) - ) - } - // check to see if we need to filter on tags - if (excludeTagArray.length && thisArticleTags.length) { - doesIncludeTag = thisArticleTags.filter((element) => - excludeTagArray.includes(element) - ) - } - - // if we didn't match any of the filtered tags or cats, then render the content - if (doesIncludeCat.length == 0 && doesIncludeTag.length == 0) { - // we need to render the Article Card view for this returned element - // **ADD DATA** - // this is my id of the article body paragraph type we need only if no thumbnail or summary provided - let bodyAndImageId = item.relationships.field_ucb_article_content.data.length ? item.relationships.field_ucb_article_content.data[0].id : ""; - let body = item.attributes.field_ucb_article_summary ? item.attributes.field_ucb_article_summary : ""; - body = body.trim(); - let imageSrc = ""; - - // if no article summary, use a simplified article body - if (!body.length && bodyAndImageId != "") { - getArticleParagraph(bodyAndImageId) - .then((response) => response.json()) - .then((data) => { - // Remove any html tags within the article - let htmlStrip = data.data.attributes.field_article_text.processed.replace( - /<\/?[^>]+(>|$)/g, - "" - ) - // Remove any line breaks if media is embedded in the body - let lineBreakStrip = htmlStrip.replace(/(\r\n|\n|\r)/gm, ""); - // take only the first 100 words ~ 500 chars - let trimmedString = lineBreakStrip.substr(0, 250); - // if in the middle of the string, take the whole word - if(trimmedString.length > 100){ - trimmedString = trimmedString.substr( - 0, - Math.min( - trimmedString.length, - trimmedString.lastIndexOf(" ") - ) + // if we didn't match any of the filtered tags or cats, then render the content + if (doesIncludeCat.length == 0 && doesIncludeTag.length == 0) { + // we need to render the Article Card view for this returned element + // **ADD DATA** + // this is my id of the article body paragraph type we need only if no thumbnail or summary provided + let bodyAndImageId = item.relationships.field_ucb_article_content.data.length ? item.relationships.field_ucb_article_content.data[0].id : ""; + let body = item.attributes.field_ucb_article_summary ? item.attributes.field_ucb_article_summary : ""; + body = body.trim(); + let imageSrc = ""; + + // if no article summary, use a simplified article body + if (!body.length && bodyAndImageId != "") { + getArticleParagraph(bodyAndImageId) + .then((response) => response.json()) + .then((data) => { + // Remove any html tags within the article + let htmlStrip = data.data.attributes.field_article_text.processed.replace( + /<\/?[^>]+(>|$)/g, + "" ) - body = `${trimmedString}...`; - } - // set the contentBody of Article Summary card to the minified body instead - body = `${trimmedString}`; - document.getElementById(`body-${bodyAndImageId}`).innerText = body; - }) - } + // Remove any line breaks if media is embedded in the body + let lineBreakStrip = htmlStrip.replace(/(\r\n|\n|\r)/gm, ""); + // take only the first 100 words ~ 500 chars + let trimmedString = lineBreakStrip.substr(0, 250); + // if in the middle of the string, take the whole word + if (trimmedString.length > 100) { + trimmedString = trimmedString.substr( + 0, + Math.min( + trimmedString.length, + trimmedString.lastIndexOf(" ") + ) + ) + body = `${trimmedString}...`; + } + // set the contentBody of Article Summary card to the minified body instead + body = `${trimmedString}`; + document.getElementById(`body-${bodyAndImageId}`).innerText = body; + }) + } - // if no thumbnail, show no image - if (!item.relationships.field_ucb_article_thumbnail.data) { - imageSrc = ""; - } else { - //Use the idObj as a memo to add the corresponding image url - let thumbId = item.relationships.field_ucb_article_thumbnail.data.id; - imageSrc = altObj[idObj[thumbId]]; - } + // if no thumbnail, show no image + if (!item.relationships.field_ucb_article_thumbnail.data) { + imageSrc = null; + } else { + //Use the idObj as a memo to add the corresponding image url + let thumbId = item.relationships.field_ucb_article_thumbnail.data.id; + imageSrc = altObj[idObj[thumbId]]; + } - //Date - make human readable - const options = { year: 'numeric', month: 'short', day: 'numeric' }; - let date = new Date(item.attributes.created).toLocaleDateString('en-us', options); - let title = item.attributes.title; - let link = item.attributes.path.alias; - let image = ""; - let articleSummarySize = "col-md-12"; + //Date - make human readable + const options = { year: 'numeric', month: 'short', day: 'numeric' }; + let date = new Date(item.attributes.created).toLocaleDateString('en-us', options); + let title = item.attributes.title; + let link = item.attributes.path.alias; + let image = ""; + let articleSummarySize = "col-md-12"; - var articleRow = document.createElement('div') - articleRow.className = 'ucb-article-card row' + var articleRow = document.createElement('div') + articleRow.className = 'ucb-article-card row' - if(link && imageSrc) { + if (link && imageSrc) { articleSummarySize = "col-md-10" var imgContainer = document.createElement('div') @@ -225,7 +227,8 @@ function renderArticleList( JSONURL, ExcludeCategories = "", ExcludeTags = "") { imgLink.href = link; var articleImg = document.createElement('img') - articleImg.src = imageSrc; + articleImg.src = imageSrc.src; + articleImg.setAttribute('alt', imageSrc.alt); imgLink.appendChild(articleImg) imgContainer.appendChild(imgLink) @@ -238,7 +241,7 @@ function renderArticleList( JSONURL, ExcludeCategories = "", ExcludeTags = "") { // Container var articleDataContainer = document.createElement('div') articleDataContainer.className = `col-sm-12 ${articleSummarySize} ucb-article-card-data` - + // Header var articleDataLink = document.createElement('a') @@ -266,7 +269,7 @@ function renderArticleList( JSONURL, ExcludeCategories = "", ExcludeTags = "") { // Read more & link var articleSummaryReadMore = document.createElement('span') articleSummaryReadMore.className = 'ucb-article-card-more' - + var readMoreLink = document.createElement('a') readMoreLink.href = link; readMoreLink.innerText = `Read more` @@ -284,41 +287,41 @@ function renderArticleList( JSONURL, ExcludeCategories = "", ExcludeTags = "") { articleDataContainer.appendChild(articleCardDate) articleDataContainer.appendChild(articleSummaryBody) articleDataContainer.appendChild(articleSummaryReadMore) - + articleRow.appendChild(articleDataContainer) - let dataOutput = document.getElementById("ucb-al-data"); - let thisArticle = document.createElement("article"); - thisArticle.className = 'ucb-article-card-container'; - thisArticle.appendChild(articleRow); - dataOutput.append(thisArticle); + let dataOutput = document.getElementById("ucb-al-data"); + let thisArticle = document.createElement("article"); + thisArticle.className = 'ucb-article-card-container'; + thisArticle.appendChild(articleRow); + dataOutput.append(thisArticle); - if(NEXTJSONURL){ - toggleMessage('ucb-el-load-more', 'inline-block') + if (NEXTJSONURL) { + toggleMessage('ucb-el-load-more', 'inline-block') + } } - } - }) - - // done loading -- hide the loading spinner graphic - toggleMessage("ucb-al-loading", "none"); - resolve(NEXTJSONURL); - }).catch(function(error) { - // catch any fetch errors and let the user know so they're not endlessly watching the spinner - console.log("Fetch Error in URL : " + JSONURL); - console.log("Fetch Error is : " + error); - // turn off spinner - toggleMessage("ucb-al-loading", "none"); - // turn on default error message - if(error){ - toggleMessage("ucb-al-error", "block"); + }) - } + // done loading -- hide the loading spinner graphic + toggleMessage("ucb-al-loading", "none"); + resolve(NEXTJSONURL); + }).catch(function (error) { + // catch any fetch errors and let the user know so they're not endlessly watching the spinner + console.log("Fetch Error in URL : " + JSONURL); + console.log("Fetch Error is : " + error); + // turn off spinner + toggleMessage("ucb-al-loading", "none"); + // turn on default error message + if (error) { + toggleMessage("ucb-al-error", "block"); + + } - }); + }); - } + } }); } @@ -339,10 +342,10 @@ function renderArticleList( JSONURL, ExcludeCategories = "", ExcludeTags = "") { CategoryExclude = el.dataset.excats; TagsExclude = el.dataset.extags; } - + // attempt to render the data requested - renderArticleList( JSONURL, CategoryExclude, TagsExclude,).then((response) => { - if(response) { + renderArticleList(JSONURL, CategoryExclude, TagsExclude,).then((response) => { + if (response) { NEXTJSONURL = "/jsonapi/" + response; } }); @@ -350,17 +353,17 @@ function renderArticleList( JSONURL, ExcludeCategories = "", ExcludeTags = "") { // watch for scrolling and determine if we're at the bottom of the content and need to request more const button = document.getElementById('ucb-el-load-more') button.addEventListener("click", function () { - if(NEXTJSONURL) { - renderArticleList( NEXTJSONURL, CategoryExclude, TagsExclude,).then((response) => { - if(response) { - NEXTJSONURL = "/jsonapi/" + response; - loadingData = false; - } else { - NEXTJSONURL = ""; - toggleMessage("ucb-al-end-of-data", "block"); - toggleMessage('ucb-el-load-more') - } - }); - } + if (NEXTJSONURL) { + renderArticleList(NEXTJSONURL, CategoryExclude, TagsExclude,).then((response) => { + if (response) { + NEXTJSONURL = "/jsonapi/" + response; + loadingData = false; + } else { + NEXTJSONURL = ""; + toggleMessage("ucb-al-end-of-data", "block"); + toggleMessage('ucb-el-load-more') + } + }); + } }) })() From d635886cf16033765bee225286c3afca291abd96 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 10:16:52 -0700 Subject: [PATCH 13/26] wip: year selects and list clears working --- js/ucb-class-notes-list.js | 54 ++++++++++++------- .../node--ucb-class-notes-list-page.html.twig | 1 + 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 95cfd307..1fa8eb70 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -3,8 +3,11 @@ class ClassNotesListElement extends HTMLElement { super(); const chromeElement = this._chromeElement = document.createElement('div'), - userFormElement = this._userFormElement = document.createElement('div'); + userFormElement = this._userFormElement = document.createElement('div'), + notesListElement = this._notesListElement = document.createElement('div'); + this._notesListElement.classList.add('ucb-class-notes-list-container') chromeElement.appendChild(userFormElement); + chromeElement.appendChild(notesListElement) this.appendChild(chromeElement); const dates = ['--Select date--', 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050] const JSONURL = this.getAttribute('base-uri'); @@ -18,7 +21,6 @@ class ClassNotesListElement extends HTMLElement { let yearFilter = ''; let publishFilter = '' // If its not a next link, build the JSON API URL - if(!next){ if (year) { yearFilter = `?filter[field_ucb_class_year]=${year}` publishFilter = '&filter[status]=1' @@ -26,21 +28,21 @@ class ClassNotesListElement extends HTMLElement { yearFilter = '' publishFilter = '?filter[status]=1' } - } const API = JSONURL + yearFilter + publishFilter fetch(API) .then(this.handleError) .then((data) => { - if (data.links.next){ + const classNotesContainer = this._notesListElement + // if (data.links.next){ data.data.forEach(note=>{ notes.push(note) }) - this.getData(data.links.next.href,'',notes,true) - } + // this.getData(data.links.next.href,'',notes,true) + // } - if(!data.links.next){ + // if(!data.links.next){ this.build(notes, year) - } + // } }) .catch(Error=> { console.error('There was an error fetching data from the API - Please try again later.') @@ -51,24 +53,28 @@ class ClassNotesListElement extends HTMLElement { } // TO DO : construct build(data, year){ - // Build container - const classNotesContainer = document.createElement('div') - classNotesContainer.classList.add('ucb-class-notes-list-container') + const classNotesContainer = this._notesListElement // Build Notes data.forEach(note => { const classNote = document.createElement('article') classNote.classList.add('ucb-class-notes-list-note-item') // Date - if(!year){ + console.log('my year', year) + const classNoteYearContainer = document.createElement('div') classNoteYearContainer.classList.add('class-note-year') - const classNoteYearLink = document.createElement('a') + const classNoteYearLink = document.createElement('a'); classNoteYearLink.href = '#'; classNoteYearLink.innerText = note.attributes.field_ucb_class_year; - classNoteYearLink.addEventListener('click', this.onYearSelect.bind(this)); + + // Use an arrow function to pass the correct argument + classNoteYearLink.addEventListener('click', (event) => { + event.preventDefault(); // Prevent default anchor behavior + this.onYearSelect(note.attributes.field_ucb_class_year); + }); classNoteYearContainer.appendChild(classNoteYearLink) classNote.appendChild(classNoteYearContainer) - } + // Class Note Text const classNoteParagraph = document.createElement('p') classNoteParagraph.innerHTML = this.escapeHTML(note.attributes.body.processed) @@ -80,7 +86,7 @@ class ClassNotesListElement extends HTMLElement { classNote.appendChild(classNotePosted) classNotesContainer.appendChild(classNote) }) - this.appendChild(classNotesContainer) + // this.appendChild(classNotesContainer) } toggleMessageDisplay(element, display, className, innerText) { if(className) @@ -166,13 +172,23 @@ class ClassNotesListElement extends HTMLElement { // Event handler for the dropdown change onYearChange(event) { const year = event.target.value; - const JSONURL = this.getAttribute('base-uri'); + const JSONURL = this.getAttribute('base-uri'); + const notesListElement = this._notesListElement + while (notesListElement.firstChild) { + notesListElement.removeChild(notesListElement.firstChild); + } this.getData(JSONURL, year); } onYearSelect(year){ - const JSONURL = this.getAttribute('base-uri') - this.getData(JSONURL, year) + const JSONURL = this.getAttribute('base-uri'); + const notesListElement = this._notesListElement; + + while (notesListElement.firstChild) { + notesListElement.removeChild(notesListElement.firstChild); + } + + this.getData(JSONURL, year); } onSortChange(event){ diff --git a/templates/content/node--ucb-class-notes-list-page.html.twig b/templates/content/node--ucb-class-notes-list-page.html.twig index 67725351..ef771ef1 100644 --- a/templates/content/node--ucb-class-notes-list-page.html.twig +++ b/templates/content/node--ucb-class-notes-list-page.html.twig @@ -36,5 +36,6 @@ 'base-uri': url('')|render|trim('/') ~ '/jsonapi/node/ucb_class_notes', })}}> +
From 343b270400134cc72f5e43bc3869f67a96b4e3dd Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 11:09:28 -0700 Subject: [PATCH 14/26] wip: sort filter --- js/ucb-class-notes-list.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 1fa8eb70..734dd0e9 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -14,12 +14,18 @@ class ClassNotesListElement extends HTMLElement { // Build user filters this.generateForm(dates) // Insert year filter, make call - this.getData(JSONURL, "") + this.getData(JSONURL, "", 'Class Year') } // Gets info - getData(JSONURL, year = '', notes = [], next = false) { + getData(JSONURL, year = '', sort, notes = []) { let yearFilter = ''; let publishFilter = '' + let sortFilter = '' + if(sort == 'Class Year'){ + sortFilter = '&sort=field_ucb_class_year' + } else { + sortFilter = '&sort=-created' + } // If its not a next link, build the JSON API URL if (year) { yearFilter = `?filter[field_ucb_class_year]=${year}` @@ -28,10 +34,12 @@ class ClassNotesListElement extends HTMLElement { yearFilter = '' publishFilter = '?filter[status]=1' } - const API = JSONURL + yearFilter + publishFilter + const API = JSONURL + yearFilter + publishFilter + sortFilter + console.log(API) fetch(API) .then(this.handleError) .then((data) => { + console.log('my data', data) const classNotesContainer = this._notesListElement // if (data.links.next){ data.data.forEach(note=>{ @@ -59,8 +67,6 @@ class ClassNotesListElement extends HTMLElement { const classNote = document.createElement('article') classNote.classList.add('ucb-class-notes-list-note-item') // Date - console.log('my year', year) - const classNoteYearContainer = document.createElement('div') classNoteYearContainer.classList.add('class-note-year') const classNoteYearLink = document.createElement('a'); @@ -193,7 +199,15 @@ class ClassNotesListElement extends HTMLElement { onSortChange(event){ const sort = event.target.value - console.log(sort) + const JSONURL = this.getAttribute('base-uri'); + const notesListElement = this._notesListElement; + + while (notesListElement.firstChild) { + notesListElement.removeChild(notesListElement.firstChild); + } + this.getData(JSONURL, "", sort); + + } // Event handler for View All -- no year specified viewAllNotes(event){ From 35468f743fc14517099866dcc7d01fc5f3f544e6 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 13:48:59 -0700 Subject: [PATCH 15/26] wip: adds message and loader toggles --- js/ucb-class-notes-list.js | 85 +++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 734dd0e9..12098739 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -4,10 +4,18 @@ class ClassNotesListElement extends HTMLElement { const chromeElement = this._chromeElement = document.createElement('div'), userFormElement = this._userFormElement = document.createElement('div'), - notesListElement = this._notesListElement = document.createElement('div'); + notesListElement = this._notesListElement = document.createElement('div'), + messageElement = this._messageElement = document.createElement('div'), + loadingElement = this._loadingElement = document.createElement('div'); + messageElement.className = 'ucb-list-msg'; + messageElement.setAttribute('hidden', ''); + loadingElement.className = 'ucb-loading-data'; + loadingElement.innerHTML = ''; this._notesListElement.classList.add('ucb-class-notes-list-container') chromeElement.appendChild(userFormElement); chromeElement.appendChild(notesListElement) + chromeElement.appendChild(messageElement); + chromeElement.appendChild(loadingElement); this.appendChild(chromeElement); const dates = ['--Select date--', 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050] const JSONURL = this.getAttribute('base-uri'); @@ -18,6 +26,7 @@ class ClassNotesListElement extends HTMLElement { } // Gets info getData(JSONURL, year = '', sort, notes = []) { + this.toggleMessageDisplay(this._loadingElement, 'block', null, null); let yearFilter = ''; let publishFilter = '' let sortFilter = '' @@ -49,49 +58,59 @@ class ClassNotesListElement extends HTMLElement { // } // if(!data.links.next){ - this.build(notes, year) + this.build(notes) // } }) .catch(Error=> { console.error('There was an error fetching data from the API - Please try again later.') console.error(Error) - this.toggleMessage('ucb-al-loading') - this.toggleMessage('ucb-al-api-error', "block") + this.toggleMessageDisplay(this._loadingElement, 'none'); + this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-api-error', 'Error retrieving data from the API endpoint. Please try again later.'); }); } // TO DO : construct - build(data, year){ + build(data){ const classNotesContainer = this._notesListElement // Build Notes - data.forEach(note => { - const classNote = document.createElement('article') - classNote.classList.add('ucb-class-notes-list-note-item') - // Date - const classNoteYearContainer = document.createElement('div') - classNoteYearContainer.classList.add('class-note-year') - const classNoteYearLink = document.createElement('a'); - classNoteYearLink.href = '#'; - classNoteYearLink.innerText = note.attributes.field_ucb_class_year; - - // Use an arrow function to pass the correct argument - classNoteYearLink.addEventListener('click', (event) => { - event.preventDefault(); // Prevent default anchor behavior - this.onYearSelect(note.attributes.field_ucb_class_year); - }); - classNoteYearContainer.appendChild(classNoteYearLink) - classNote.appendChild(classNoteYearContainer) + console.log('i am building', data) + if(data.length == 0){ + // TO DO -- add no results errors + this.toggleMessageDisplay(this._loadingElement, 'none', null, null); + this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-end-of-results', 'No results matching your filters.'); + console.log('No results') + } else { + data.forEach(note => { + const classNote = document.createElement('article') + classNote.classList.add('ucb-class-notes-list-note-item') + // Date + const classNoteYearContainer = document.createElement('div') + classNoteYearContainer.classList.add('class-note-year') + const classNoteYearLink = document.createElement('a'); + classNoteYearLink.href = '#'; + classNoteYearLink.innerText = note.attributes.field_ucb_class_year; + + // Use an arrow function to pass the correct argument + classNoteYearLink.addEventListener('click', (event) => { + event.preventDefault(); // Prevent default anchor behavior + this.onYearSelect(note.attributes.field_ucb_class_year); + }); + classNoteYearContainer.appendChild(classNoteYearLink) + classNote.appendChild(classNoteYearContainer) + + // Class Note Text + const classNoteParagraph = document.createElement('p') + classNoteParagraph.innerHTML = this.escapeHTML(note.attributes.body.processed) + classNote.appendChild(classNoteParagraph) + // Date posted + const classNotePosted = document.createElement('p') + classNotePosted.classList.add('class-note-posted-date') + classNotePosted.innerText = `Posted ${this.formatDateString(note.attributes.created)}` + classNote.appendChild(classNotePosted) + this.toggleMessageDisplay(this._loadingElement, 'none', null, null); - // Class Note Text - const classNoteParagraph = document.createElement('p') - classNoteParagraph.innerHTML = this.escapeHTML(note.attributes.body.processed) - classNote.appendChild(classNoteParagraph) - // Date posted - const classNotePosted = document.createElement('p') - classNotePosted.classList.add('class-note-posted-date') - classNotePosted.innerText = `Posted ${this.formatDateString(note.attributes.created)}` - classNote.appendChild(classNotePosted) - classNotesContainer.appendChild(classNote) - }) + classNotesContainer.appendChild(classNote) + }) + } // this.appendChild(classNotesContainer) } toggleMessageDisplay(element, display, className, innerText) { From 36a5cfdb4926b622aab89c2c7bfdde886348ee97 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 14:01:31 -0700 Subject: [PATCH 16/26] wip: View all working, need a button to load addtl notes --- js/ucb-class-notes-list.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 12098739..159affd9 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -27,6 +27,7 @@ class ClassNotesListElement extends HTMLElement { // Gets info getData(JSONURL, year = '', sort, notes = []) { this.toggleMessageDisplay(this._loadingElement, 'block', null, null); + this.toggleMessageDisplay(this._messageElement, 'none', null, null); let yearFilter = ''; let publishFilter = '' let sortFilter = '' @@ -44,7 +45,6 @@ class ClassNotesListElement extends HTMLElement { publishFilter = '?filter[status]=1' } const API = JSONURL + yearFilter + publishFilter + sortFilter - console.log(API) fetch(API) .then(this.handleError) .then((data) => { @@ -232,6 +232,13 @@ class ClassNotesListElement extends HTMLElement { viewAllNotes(event){ event.preventDefault(); console.log('View all notes pressed') + const JSONURL = this.getAttribute('base-uri'); + const notesListElement = this._notesListElement; + + while (notesListElement.firstChild) { + notesListElement.removeChild(notesListElement.firstChild); + } + this.getData(JSONURL, "" ) } escapeHTML(raw) { From 347351a188ea2122511323929802f3003667fa84 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 15:02:53 -0700 Subject: [PATCH 17/26] wip: adds load more button, end of results messaging --- js/ucb-class-notes-list.js | 42 ++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 159affd9..d6265cb7 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -25,7 +25,7 @@ class ClassNotesListElement extends HTMLElement { this.getData(JSONURL, "", 'Class Year') } // Gets info - getData(JSONURL, year = '', sort, notes = []) { + getData(JSONURL, year = '', sort, notes = [], nextURL = "") { this.toggleMessageDisplay(this._loadingElement, 'block', null, null); this.toggleMessageDisplay(this._messageElement, 'none', null, null); let yearFilter = ''; @@ -44,12 +44,11 @@ class ClassNotesListElement extends HTMLElement { yearFilter = '' publishFilter = '?filter[status]=1' } - const API = JSONURL + yearFilter + publishFilter + sortFilter + const API = nextURL != "" ? nextURL : JSONURL + yearFilter + publishFilter + sortFilter fetch(API) .then(this.handleError) .then((data) => { - console.log('my data', data) - const classNotesContainer = this._notesListElement + const nextURL = data.links.next ? data.links.next.href : ""; // if (data.links.next){ data.data.forEach(note=>{ notes.push(note) @@ -58,7 +57,7 @@ class ClassNotesListElement extends HTMLElement { // } // if(!data.links.next){ - this.build(notes) + this.build(notes, nextURL) // } }) .catch(Error=> { @@ -68,16 +67,12 @@ class ClassNotesListElement extends HTMLElement { this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-api-error', 'Error retrieving data from the API endpoint. Please try again later.'); }); } - // TO DO : construct - build(data){ + build(data, nextURL){ const classNotesContainer = this._notesListElement // Build Notes - console.log('i am building', data) if(data.length == 0){ - // TO DO -- add no results errors this.toggleMessageDisplay(this._loadingElement, 'none', null, null); this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-end-of-results', 'No results matching your filters.'); - console.log('No results') } else { data.forEach(note => { const classNote = document.createElement('article') @@ -110,6 +105,21 @@ class ClassNotesListElement extends HTMLElement { classNotesContainer.appendChild(classNote) }) + } + // Makes the next button + if(nextURL != ""){ + const nextButton = document.createElement('button'); // Changed to button for better semantics + nextButton.classList.add('ucb-class-notes-read-more'); + nextButton.innerText = 'Load More Notes'; + nextButton.addEventListener('click', () => { + this.getNextSet(nextURL); + nextButton.remove(); // Remove the button after it's clicked + }); + + // Append the button to the container or a specific element + this._notesListElement.appendChild(nextButton); + } else { + this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-end-of-results', 'End of results'); } // this.appendChild(classNotesContainer) } @@ -231,7 +241,6 @@ class ClassNotesListElement extends HTMLElement { // Event handler for View All -- no year specified viewAllNotes(event){ event.preventDefault(); - console.log('View all notes pressed') const JSONURL = this.getAttribute('base-uri'); const notesListElement = this._notesListElement; @@ -262,6 +271,17 @@ class ClassNotesListElement extends HTMLElement { return date.toLocaleDateString('en-US', options); } + getNextSet(nextURL){ + // Remove existing 'Load More Notes' button + const loadMoreButton = this.querySelector('.ucb-class-notes-read-more'); + if (loadMoreButton) { + loadMoreButton.remove(); + } + + // Call API and update data + this.getData(nextURL); + } + handleError = response => { if (!response.ok) { throw new Error; From 1e87181046d150340db8678063f627722c2f53b8 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 15:08:40 -0700 Subject: [PATCH 18/26] wip: Log cleanup, notes --- js/ucb-class-notes-list.js | 39 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index d6265cb7..11588503 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -49,16 +49,12 @@ class ClassNotesListElement extends HTMLElement { .then(this.handleError) .then((data) => { const nextURL = data.links.next ? data.links.next.href : ""; - // if (data.links.next){ + // Iterate over all notes data.data.forEach(note=>{ notes.push(note) }) - // this.getData(data.links.next.href,'',notes,true) - // } - - // if(!data.links.next){ this.build(notes, nextURL) - // } + }) .catch(Error=> { console.error('There was an error fetching data from the API - Please try again later.') @@ -67,6 +63,7 @@ class ClassNotesListElement extends HTMLElement { this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-api-error', 'Error retrieving data from the API endpoint. Please try again later.'); }); } + // Render handler build(data, nextURL){ const classNotesContainer = this._notesListElement // Build Notes @@ -77,14 +74,13 @@ class ClassNotesListElement extends HTMLElement { data.forEach(note => { const classNote = document.createElement('article') classNote.classList.add('ucb-class-notes-list-note-item') - // Date + // Date (Class Note Link) const classNoteYearContainer = document.createElement('div') classNoteYearContainer.classList.add('class-note-year') const classNoteYearLink = document.createElement('a'); classNoteYearLink.href = '#'; classNoteYearLink.innerText = note.attributes.field_ucb_class_year; - - // Use an arrow function to pass the correct argument + // Class Note Link Event Listener classNoteYearLink.addEventListener('click', (event) => { event.preventDefault(); // Prevent default anchor behavior this.onYearSelect(note.attributes.field_ucb_class_year); @@ -108,7 +104,7 @@ class ClassNotesListElement extends HTMLElement { } // Makes the next button if(nextURL != ""){ - const nextButton = document.createElement('button'); // Changed to button for better semantics + const nextButton = document.createElement('button'); nextButton.classList.add('ucb-class-notes-read-more'); nextButton.innerText = 'Load More Notes'; nextButton.addEventListener('click', () => { @@ -118,11 +114,9 @@ class ClassNotesListElement extends HTMLElement { // Append the button to the container or a specific element this._notesListElement.appendChild(nextButton); - } else { - this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-end-of-results', 'End of results'); - } - // this.appendChild(classNotesContainer) + } } + // Used for toggling the error messages/loader on/off toggleMessageDisplay(element, display, className, innerText) { if(className) element.className = className; @@ -132,7 +126,7 @@ class ClassNotesListElement extends HTMLElement { element.setAttribute('hidden', ''); else element.removeAttribute('hidden'); } - + // Builds the user forms generateForm(dates){ // Create Elements const form = document.createElement('form'), @@ -190,7 +184,7 @@ class ClassNotesListElement extends HTMLElement { form.appendChild(viewAllLinkContainer); this._userFormElement.appendChild(form); } - + // Generates the Dropdowns, on the user form generateDropdown(dates, selectElement){ dates.map(date => { const option = document.createElement('option'); @@ -203,7 +197,6 @@ class ClassNotesListElement extends HTMLElement { selectElement.appendChild(option); }) } - // Event handler for the dropdown change onYearChange(event) { const year = event.target.value; @@ -214,7 +207,7 @@ class ClassNotesListElement extends HTMLElement { } this.getData(JSONURL, year); } - + // If a Class Note Year is selected... onYearSelect(year){ const JSONURL = this.getAttribute('base-uri'); const notesListElement = this._notesListElement; @@ -225,7 +218,7 @@ class ClassNotesListElement extends HTMLElement { this.getData(JSONURL, year); } - + // Event handler for Sort filter dropdown change onSortChange(event){ const sort = event.target.value const JSONURL = this.getAttribute('base-uri'); @@ -249,7 +242,7 @@ class ClassNotesListElement extends HTMLElement { } this.getData(JSONURL, "" ) } - + // Prevents malicious user input escapeHTML(raw) { if (!raw) return ''; @@ -264,13 +257,13 @@ class ClassNotesListElement extends HTMLElement { return escapedHTML; } - + // Date formatter formatDateString(dateString) { const options = { year: 'numeric', month: 'short', day: 'numeric' }; const date = new Date(dateString); return date.toLocaleDateString('en-US', options); } - + // Used for loading articles beyond 50, sets up next API calls getNextSet(nextURL){ // Remove existing 'Load More Notes' button const loadMoreButton = this.querySelector('.ucb-class-notes-read-more'); @@ -281,7 +274,7 @@ class ClassNotesListElement extends HTMLElement { // Call API and update data this.getData(nextURL); } - + // Error handler handleError = response => { if (!response.ok) { throw new Error; From f5e1077f00393cc796f088d1f0bf3dee7fb0fc6a Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 15:16:51 -0700 Subject: [PATCH 19/26] wip: fix messaging --- js/ucb-class-notes-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 11588503..253758e2 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -67,7 +67,7 @@ class ClassNotesListElement extends HTMLElement { build(data, nextURL){ const classNotesContainer = this._notesListElement // Build Notes - if(data.length == 0){ + if(!data.length){ this.toggleMessageDisplay(this._loadingElement, 'none', null, null); this.toggleMessageDisplay(this._messageElement, 'block', 'ucb-list-msg ucb-end-of-results', 'No results matching your filters.'); } else { From 63ef8916c63ab20feb8e721af17ebc0c3867b5e1 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 15:27:14 -0700 Subject: [PATCH 20/26] wip: checks other filters on change, clear list refactor --- js/ucb-class-notes-list.js | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 253758e2..fc0ce5db 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -200,46 +200,40 @@ class ClassNotesListElement extends HTMLElement { // Event handler for the dropdown change onYearChange(event) { const year = event.target.value; - const JSONURL = this.getAttribute('base-uri'); + const JSONURL = this.getAttribute('base-uri'); + const sort = this.getSortValue(); const notesListElement = this._notesListElement while (notesListElement.firstChild) { notesListElement.removeChild(notesListElement.firstChild); } - this.getData(JSONURL, year); + this.getData(JSONURL, year, sort); } // If a Class Note Year is selected... onYearSelect(year){ const JSONURL = this.getAttribute('base-uri'); - const notesListElement = this._notesListElement; - - while (notesListElement.firstChild) { - notesListElement.removeChild(notesListElement.firstChild); - } - + this.clearNotesList() this.getData(JSONURL, year); } // Event handler for Sort filter dropdown change onSortChange(event){ const sort = event.target.value const JSONURL = this.getAttribute('base-uri'); + const year = this.getYearValue(); + this.clearNotesList() + this.getData(JSONURL, year, sort); + } + // Helper method to clear the notes list + clearNotesList() { const notesListElement = this._notesListElement; - while (notesListElement.firstChild) { notesListElement.removeChild(notesListElement.firstChild); } - this.getData(JSONURL, "", sort); - - } // Event handler for View All -- no year specified viewAllNotes(event){ event.preventDefault(); const JSONURL = this.getAttribute('base-uri'); - const notesListElement = this._notesListElement; - - while (notesListElement.firstChild) { - notesListElement.removeChild(notesListElement.firstChild); - } + this.clearNotesList() this.getData(JSONURL, "" ) } // Prevents malicious user input @@ -274,6 +268,15 @@ class ClassNotesListElement extends HTMLElement { // Call API and update data this.getData(nextURL); } + // Helper method to get the current year value from the dropdown + getYearValue() { + return this.querySelector('.Year.Select').value; + } + + // Helper method to get the current sort value from the dropdown + getSortValue() { + return this.querySelector('.Sort.Select').value; + } // Error handler handleError = response => { if (!response.ok) { From 4e7d1677c64e5d0ed3c6032ba74b3b6b2b0443b8 Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 17 Jan 2024 15:30:41 -0700 Subject: [PATCH 21/26] wip: dropdown reset when View All --- js/ucb-class-notes-list.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index fc0ce5db..531c2d29 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -232,6 +232,7 @@ class ClassNotesListElement extends HTMLElement { // Event handler for View All -- no year specified viewAllNotes(event){ event.preventDefault(); + this.resetDropdowns(); const JSONURL = this.getAttribute('base-uri'); this.clearNotesList() this.getData(JSONURL, "" ) @@ -277,6 +278,16 @@ class ClassNotesListElement extends HTMLElement { getSortValue() { return this.querySelector('.Sort.Select').value; } + // Dropdown resetter + resetDropdowns() { + const yearDropdown = this.querySelector('.Year.Select'); + const sortDropdown = this.querySelector('.Sort.Select'); + + if (yearDropdown && sortDropdown) { + yearDropdown.value = ''; + sortDropdown.value = 'Class Year'; + } + } // Error handler handleError = response => { if (!response.ok) { From b4d69e35334b89dfe0741ea297dd6c9770527cc0 Mon Sep 17 00:00:00 2001 From: Timur Tripp Date: Wed, 17 Jan 2024 16:02:27 -0700 Subject: [PATCH 22/26] CuBoulder/tiamat-theme#616 fixes article title background bugs --- css/ucb-article.css | 56 +++++++++++-------- templates/content/node--ucb-article.html.twig | 10 ++-- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/css/ucb-article.css b/css/ucb-article.css index 56b45410..fba7ed70 100644 --- a/css/ucb-article.css +++ b/css/ucb-article.css @@ -131,7 +131,7 @@ i.fa-regular.fa-calendar { margin-bottom: 20px; } -.ucb-article-author-name span:not(:last-of-type):after{ +.ucb-article-author-name span:not(:last-of-type):after { content: ","; } @@ -142,50 +142,58 @@ i.fa-regular.fa-calendar { object-fit: fill; } -.centeredTitle { +.backgroundTitleDiv .ucb-article-heading { position: absolute; - bottom: 0.5em; + display: block; + bottom: 0; + width: 100%; + background-color: transparent; + padding: 200px 20px 30px; +} + +.backgroundTitleDiv.ucb-overlay-dark .ucb-article-heading { + background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.85)); + background-image: -moz-linear-gradient(top, transparent, rgba(0, 0, 0, 0.85)); + background-image: -o-linear-gradient(top, transparent, rgba(0, 0, 0, 0.85)); + background-image: -ms-linear-gradient(top, transparent, rgba(0, 0, 0, 0.85)); + background-image: linear-gradient(top, transparent, rgba(0, 0, 0, 0.85)); +} + +.backgroundTitleDiv.ucb-overlay-light .ucb-article-heading { + background-image: -webkit-linear-gradient(top, transparent, rgba(255, 255, 255, 0.85)); + background-image: -moz-linear-gradient(top, transparent, rgba(255, 255, 255, 0.85)); + background-image: -o-linear-gradient(top, transparent, rgba(255, 255, 255, 0.85)); + background-image: -ms-linear-gradient(top, transparent, rgba(255, 255, 255, 0.85)); + background-image: linear-gradient(top, transparent, rgba(255, 255, 255, 0.85)); } -.article-header-White{ - color: white; +.ucb-article-heading.article-header-White, .ucb-article-heading.article-header-White h1 { + color: #FFF; } -.article-header-Black{ - color:black +.ucb-article-heading.article-header-Black, .ucb-article-heading.article-header-Black h1 { + color: #000; } -.backgroundTitleDiv > div > div > .imageMediaStyle > img { +.backgroundTitleDiv .imageMediaStyle img { width: 100%; max-height: 600px; object-fit: cover; } -.backgroundTitleDiv > div > div > .imageMediaStyle{ +.backgroundTitleDiv .imageMediaStyle { padding-bottom: 0; margin-bottom: 20px; } -.ucb-overlay-dark > div > div > .imageMediaStyle > img, -.ucb-overlay-light > div > div > .imageMediaStyle > img{ - opacity: 75%; -} - -.ucb-overlay-light > div > div > .imageMediaStyle{ - background: white; -} -.ucb-overlay-dark > div > div > .imageMediaStyle{ - background: black; -} - -.ucb-article-supplemental-text{ +.ucb-article-supplemental-text { margin-bottom: 1em; font-style: italic; font-size: 0.85em; } /* Removes caption on header img */ -.backgroundTitleDiv > div > div > .media-image-caption{ +.backgroundTitleDiv .media-image-caption { display: none; } @@ -194,6 +202,6 @@ i.fa-regular.fa-calendar { display: block; } -.backgroundTitleDiv .imageMediaStyle img{ +.backgroundTitleDiv .imageMediaStyle img { padding-bottom: 0px; } diff --git a/templates/content/node--ucb-article.html.twig b/templates/content/node--ucb-article.html.twig index ab604a5b..2544eb8f 100644 --- a/templates/content/node--ucb-article.html.twig +++ b/templates/content/node--ucb-article.html.twig @@ -143,10 +143,12 @@

{{ label }}

{{ content.field_article_title_background }} -
- - {{ label }} - + +
+

+ {{ label }} +

+
{% endif %} From 7984ccf00891ffb4a0b2a9349c1ba9a47bfed2e4 Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 18 Jan 2024 09:39:53 -0700 Subject: [PATCH 23/26] wip: styling pass --- css/ucb-class-notes-list.css | 40 ++++++++++++++++++++++++++++++++++++ js/ucb-class-notes-list.js | 22 ++++++++++---------- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/css/ucb-class-notes-list.css b/css/ucb-class-notes-list.css index 9edef803..9f0b90e1 100644 --- a/css/ucb-class-notes-list.css +++ b/css/ucb-class-notes-list.css @@ -1,3 +1,36 @@ +.ucb-class-note-link{ + font-size: 200%; + font-weight: 700; + color: #959595 !important; + margin-bottom: 10px; +} + +.ucb-class-note-year-container{ + margin-bottom: 10px; +} + +.ucb-class-note-link:hover{ + color: #333 !important; +} + +.ucb-class-notes-list-container{ + margin-top: 20px; +} + +.class-note-posted-date{ + font-size: 75%; +} + +.ucb-class-notes-list-note-item{ + margin-bottom: 20px; + border-bottom: 1px solid rgba(128, 128, 128, 0.333); + /* padding-bottom: 20px; */ +} + +.class-note-year-select, .ucb-class-notes-filter-label{ + margin-right: 10px; +} + .ucb-list-msg { font-size: 1.25em; font-weight: bolder; @@ -37,4 +70,11 @@ flex: 1; text-align: right; font-size: 85%; +} + +@media only screen and (max-width: 525px) { + .ucb-class-notes-view-all-container{ + flex: auto; + text-align: inherit; + } } \ No newline at end of file diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 531c2d29..75cbc97f 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -11,12 +11,12 @@ class ClassNotesListElement extends HTMLElement { messageElement.setAttribute('hidden', ''); loadingElement.className = 'ucb-loading-data'; loadingElement.innerHTML = ''; - this._notesListElement.classList.add('ucb-class-notes-list-container') + this._notesListElement.classList.add('ucb-class-notes-list-container') chromeElement.appendChild(userFormElement); chromeElement.appendChild(notesListElement) chromeElement.appendChild(messageElement); chromeElement.appendChild(loadingElement); - this.appendChild(chromeElement); + this.appendChild(chromeElement); const dates = ['--Select date--', 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050] const JSONURL = this.getAttribute('base-uri'); // Build user filters @@ -24,7 +24,7 @@ class ClassNotesListElement extends HTMLElement { // Insert year filter, make call this.getData(JSONURL, "", 'Class Year') } -// Gets info + // Gets info getData(JSONURL, year = '', sort, notes = [], nextURL = "") { this.toggleMessageDisplay(this._loadingElement, 'block', null, null); this.toggleMessageDisplay(this._messageElement, 'none', null, null); @@ -76,8 +76,9 @@ class ClassNotesListElement extends HTMLElement { classNote.classList.add('ucb-class-notes-list-note-item') // Date (Class Note Link) const classNoteYearContainer = document.createElement('div') - classNoteYearContainer.classList.add('class-note-year') + classNoteYearContainer.classList.add('ucb-class-note-year-container') const classNoteYearLink = document.createElement('a'); + classNoteYearLink.classList.add('ucb-class-note-link') classNoteYearLink.href = '#'; classNoteYearLink.innerText = note.attributes.field_ucb_class_year; // Class Note Link Event Listener @@ -145,7 +146,7 @@ class ClassNotesListElement extends HTMLElement { // Create select el const selectFilter = document.createElement('select'); selectFilter.name = "Year" - selectFilter.className = 'Year Select'; + selectFilter.classList.add('Year-Select', 'class-note-year-select'); selectFilter.onchange = this.onYearChange.bind(this); // Bind the event handler itemLabel.appendChild(selectFilter); container.appendChild(itemLabel); @@ -165,7 +166,7 @@ class ClassNotesListElement extends HTMLElement { sortItemLabel.appendChild(sortItemLabelSpan); const sortSelectFilter = document.createElement('select'); sortSelectFilter.name = "Sort" - sortSelectFilter.className = 'Sort Select'; + sortSelectFilter.classList.add('Sort-Select','class-note-sort-select'); sortSelectFilter.onchange = this.onSortChange.bind(this); // Bind the event handler sortItemLabel.appendChild(sortSelectFilter); container.appendChild(sortItemLabel); @@ -271,17 +272,16 @@ class ClassNotesListElement extends HTMLElement { } // Helper method to get the current year value from the dropdown getYearValue() { - return this.querySelector('.Year.Select').value; + return this.querySelector('.class-note-year-select').value; } - // Helper method to get the current sort value from the dropdown getSortValue() { - return this.querySelector('.Sort.Select').value; + return this.querySelector('.class-note-sort-select').value; } // Dropdown resetter resetDropdowns() { - const yearDropdown = this.querySelector('.Year.Select'); - const sortDropdown = this.querySelector('.Sort.Select'); + const yearDropdown = this.querySelector('.class-note-year-select'); + const sortDropdown = this.querySelector('.class-note-sort-select'); if (yearDropdown && sortDropdown) { yearDropdown.value = ''; From 7d70f4a04f364b05132f324a0131db647441b6c3 Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 18 Jan 2024 11:50:44 -0700 Subject: [PATCH 24/26] wip: year selection updates dropdown values, fixes View All --- js/ucb-class-notes-list.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index 75cbc97f..e0c7e042 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -212,6 +212,9 @@ class ClassNotesListElement extends HTMLElement { // If a Class Note Year is selected... onYearSelect(year){ const JSONURL = this.getAttribute('base-uri'); + const yearDropdown = this.querySelector('.class-note-year-select'); + yearDropdown.value = year; + this.clearNotesList() this.getData(JSONURL, year); } @@ -236,7 +239,7 @@ class ClassNotesListElement extends HTMLElement { this.resetDropdowns(); const JSONURL = this.getAttribute('base-uri'); this.clearNotesList() - this.getData(JSONURL, "" ) + this.getData(JSONURL, "", "Class Year") } // Prevents malicious user input escapeHTML(raw) { From a9829e85605af0e24fec2cc471257079064139f0 Mon Sep 17 00:00:00 2001 From: Pat Date: Thu, 18 Jan 2024 12:02:14 -0700 Subject: [PATCH 25/26] Additional styles --- css/ucb-class-notes-list.css | 21 +++++++++++++++++++++ js/ucb-class-notes-list.js | 13 ++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/css/ucb-class-notes-list.css b/css/ucb-class-notes-list.css index 9f0b90e1..8a2bc3dc 100644 --- a/css/ucb-class-notes-list.css +++ b/css/ucb-class-notes-list.css @@ -71,6 +71,27 @@ text-align: right; font-size: 85%; } +.ucb-class-notes-read-more-container{ + text-align: center; +} +.ucb-class-notes-read-more{ + padding: 5px 10px; + font-weight: bold; + font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif; + margin-bottom: 5px; + background-clip: padding-box; + color: #0277BD !important; + border: 1px solid #0277BD; + border-radius: 0px; + background-color: transparent; + text-decoration: none; +} + +.ucb-class-notes-read-more:hover { + transition: background-color 0.25s ease,border-color 0.25s ease,color 0.25s ease; + background-color: #0277BD; + color: white !important; +} @media only screen and (max-width: 525px) { .ucb-class-notes-view-all-container{ diff --git a/js/ucb-class-notes-list.js b/js/ucb-class-notes-list.js index e0c7e042..8e630976 100644 --- a/js/ucb-class-notes-list.js +++ b/js/ucb-class-notes-list.js @@ -105,6 +105,8 @@ class ClassNotesListElement extends HTMLElement { } // Makes the next button if(nextURL != ""){ + const nextButtonContainer = document.createElement('div') + nextButtonContainer.classList.add('ucb-class-notes-read-more-container') const nextButton = document.createElement('button'); nextButton.classList.add('ucb-class-notes-read-more'); nextButton.innerText = 'Load More Notes'; @@ -112,9 +114,9 @@ class ClassNotesListElement extends HTMLElement { this.getNextSet(nextURL); nextButton.remove(); // Remove the button after it's clicked }); - - // Append the button to the container or a specific element - this._notesListElement.appendChild(nextButton); + // Append the button to the container, then the element + nextButtonContainer.appendChild(nextButton) + this._notesListElement.appendChild(nextButtonContainer); } } // Used for toggling the error messages/loader on/off @@ -203,10 +205,7 @@ class ClassNotesListElement extends HTMLElement { const year = event.target.value; const JSONURL = this.getAttribute('base-uri'); const sort = this.getSortValue(); - const notesListElement = this._notesListElement - while (notesListElement.firstChild) { - notesListElement.removeChild(notesListElement.firstChild); - } + this.clearNotesList(); this.getData(JSONURL, year, sort); } // If a Class Note Year is selected... From 0ac21d503617ae20ff48ae2c81a4c158ad56114e Mon Sep 17 00:00:00 2001 From: Timur Tripp Date: Mon, 22 Jan 2024 11:36:05 -0700 Subject: [PATCH 26/26] CuBoulder/tiamat-theme#614 fixes expandable content `aria-expanded`/`aria-selected` errors --- templates/block/block--expandable-content.html.twig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/block/block--expandable-content.html.twig b/templates/block/block--expandable-content.html.twig index b99d99a4..cb7644bd 100644 --- a/templates/block/block--expandable-content.html.twig +++ b/templates/block/block--expandable-content.html.twig @@ -26,7 +26,7 @@

{% set expandableHeaderID = item.entity.field_expandable_content_title|view %} - + {{ item.entity.field_expandable_content_title|view }} @@ -53,7 +53,7 @@ @@ -65,7 +65,7 @@