PageSourceSearch

https://www.coffeehouseexpress.com/mm5/json.mvc?Store_Code=CHE&Fun…=mmx-category-list&T=e42d2adf

js coffeehouseexpress.com collected 2026-10-04 13:15:52 UTC 5,913 bytes, 255 lines download raw bytes

1/**
2 * MMX / CATEGORY LIST
3 */
4class MMX_CategoryList extends MMX_Element {
5
6	static get props() {
7		return {
8			'category-fallback-image': {
9				allowAny: true
10			}
11		};
12	}
13
14	styleResourceCodes = ['mmx-base', 'mmx-category-list'];
15	#categories = [];
16	#card = {};
17	#errorMessage = '';
18	lifecycleReady = false;
19
20	constructor() {
21		super();
22		this.makeComponent();
23		this.bindRevealElement();
24	}
25
26	// Rendering
27	render() {
28		return /*html*/`
29			<div part="wrapper">
30				<div part="title">
31					<slot name="title"></slot>
32				</div>
33				${this.#renderMain()}
34			</div>
35		`;
36	}
37
38	afterRender() {
39		this.#replaceCategories();
40	}
41
42	onDataChange() {
43		MMX.setElementAttributes(this, {
44			'data-category-fallback-image': this.data?.fallback_category_image,
45		});
46
47		this.#card = this.data.card;
48		this.#loadCategories();
49	}
50
51	#renderMain() {
52		if (this.#errorMessage) {
53			return this.#renderMainError();
54		}
55		else {
56			return this.#renderCategories();
57		}
58	}
59
60	#renderMainError() {
61		return /*html*/`
62			<div part="error" class="mmx-category-list__error">
63				<mmx-message data-style="warning">We're unable to display the categories: ${MMX.encodeEntities(this.#errorMessage ?? 'There was a problem loading the categories')}</mmx-message>
64			</div>
65		`;
66	}
67
68	// Styles
69	styles() {
70		return this.renderResponsiveSettingStyles();
71	}
72
73	renderResponsiveSettingStyles() {
74		let breakpointStyles = this.#renderBreakpointRule(this.data?.list?.responsive_settings?.breakpoints?.default);
75
76		MMX.getBreakpoints().map(breakpoint => {
77			const settings = this.data?.list?.responsive_settings?.breakpoints?.[breakpoint?.code] ?? {};
78			breakpointStyles += '\n\n' + this.#renderBreakpointMedia({breakpoint, settings});
79		});
80
81		return breakpointStyles;
82	}
83
84	#renderBreakpointMedia({breakpoint = {}, settings = {}} = {}) {
85		if (MMX.variableType(breakpoint) !== 'object' || MMX.variableType(settings) !== 'object') {
86			return '';
87		}
88
89		return /*css*/`
90			@media ${MMX.buildMediaQuery({breakpoint})} {
91				${this.#renderBreakpointRule(settings)}
92			}
93		`;
94	}
95
96	#renderBreakpointRule(settings = {}) {
97		if (MMX.variableType(settings) !== 'object') {
98			return '';
99		}
100
101		const columns = MMX.coerceNumber(settings?.columns?.value, 1);
102		const gap = MMX.composeUnitValue(settings?.gap, {
103			fallbackUnit: 'vw'
104		}) ?? '1vw';
105
106		return /*css*/`
107			.mmx-category-list__categories {
108				--mmx-category-list__columns: ${columns};
109				--mmx-category-list__gap: ${gap};
110			}
111		`;
112	}
113
114	// Runtime_CategoryList_Load_Query
115	#loadCategories() {
116		this.#categories = [];
117		this.#errorMessage = '';
118
119		MMX.Runtime_JSON_API_Call({
120			params: this.#getListLoadQueryParams()
121		})
122		.then(response => {
123			this.#categoriesLoaded(response);
124		})
125		.catch(response => {
126			this.#categoriesFailedToLoad(response);
127		});
128	}
129
130	#categoriesLoaded(response) {
131		this.#categories = response.data.data;
132		this.forceUpdate();
133	}
134
135	#categoriesFailedToLoad(response) {
136		this.#errorMessage = response.error_message;
137		this.forceUpdate();
138	}
139
140	#getListLoadQueryParams() {
141		const Parent_Id = MMX.coerceNumber(this.data?.list?.parent_category?.specific?.category?.id, 0);
142
143		return {
144			Function: 'Runtime_CategoryList_Load_Query',
145			Filter: this.#getFilters(),
146			Parent_Id
147		};
148	}
149
150	#getCacheKeysFilters() {
151		return MMX.cacheKeysFilters(this.data?.list?.parent_category?.specific?.category);
152	}
153
154	#getFilters() {
155		const details = this.#getCardDetails();
156		const filters = details.reduce((filters, detail) => {
157			const type = detail?.type?.value;
158
159			if (type === 'customfield' && !MMX.valueIsEmpty(detail?.customfield?.value)) {
160				filters.push({
161					name: 'ondemandcolumns',
162					value: [`CustomField_Values:${detail.customfield.value}`]
163				});
164			}
165			else if (type === 'fragment' && !MMX.valueIsEmpty(detail?.fragment?.value)) {
166				filters.push({
167					name: 'fragments',
168					value: [detail.fragment.value]
169				});
170			}
171			else if (type === 'image') {
172				const imageType = detail?.image_settings?.type?.value;
173
174				if (imageType === 'cattitle') {
175					filters.push({
176						name: 'ondemandcolumns',
177						value: ['CustomField_Values:cmp-cssui-cattitle:category_title_image']
178					});
179				}
180				else if (imageType === 'cattree') {
181					filters.push({
182						name: 'ondemandcolumns',
183						value: ['CustomField_Values:cmp-cssui-cattree:category_tree_image']
184					});
185				}
186			}
187
188			return filters;
189		}, []);
190
191		filters.push(...this.#getCacheKeysFilters());
192
193		return filters;
194	}
195
196	// Categories
197	#renderCategories() {
198		if (MMX.arrayIsEmpty(this.#categories)) {
199			return '';
200		}
201
202		return /*html*/`
203			<div
204				class="mmx-category-list__categories"
205				part="categories"
206			>
207				<slot name="categories"></slot>
208			</div>
209		`;
210	}
211
212	#categoriesContainer() {
213		return this.querySelector('[slot="categories"]');
214	}
215
216	#replaceCategories() {
217		this.renderContentIntoLightDomSlot({slotName: 'categories', content: ''});
218		this.#categoriesContainer()?.replaceChildren?.(this.#createCategories());
219	}
220
221	#createCategories() {
222		if (!Array.isArray(this.#categories)) {
223			return '';
224		}
225
226		const parent = new DocumentFragment();
227		const details = this.#getCardDetails();
228		const styles = this.#card?.styles ?? {};
229		const attributes = {
230			'data-fallback-image': this.getPropValue('category-fallback-image'),
231			'data-image-fit': this.getPropValue('category-image-fit'),
232			'data-image-type': this.getPropValue('category-image-type')
233		};
234
235		const content = /*html*/`
236			${this.renderThemeStylesheetTemplate(true)}
237		`;
238
239		this.#categories.forEach(category => {
240			attributes['data-category-code'] = category.code;
241			MMX_CategoryCard.create({category, details, styles, parent, attributes, content});
242		});
243
244		return parent;
245	}
246
247	#getCardDetails() {
248		const details = this.#card?.details?.children;
249		return Array.isArray(details) ? details : [];
250	}
251}
252
253if (!customElements.get('mmx-category-list')) {
254	customElements.define('mmx-category-list', MMX_CategoryList);
255}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.