@occluze/tether 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -21
- package/dist/esm/chunks/{account-UIPWJQ3Y.js → account-CXMA5RPZ.js} +1 -1
- package/dist/esm/chunks/{account-pages-6ROA6Y4V.js → account-pages-IZO7FEOZ.js} +1 -1
- package/dist/esm/chunks/{analytics-2V632IRV.js → analytics-PG5FPRDN.js} +1 -1
- package/dist/esm/chunks/{chunk-4GCXM764.js → chunk-4HD4J5JC.js} +1 -1
- package/dist/esm/chunks/{chunk-BFTZR4OB.js → chunk-6TFMLT4A.js} +2 -2
- package/dist/esm/chunks/{chunk-T44MUL4Y.js → chunk-BBVUVPMO.js} +1 -1
- package/dist/esm/chunks/chunk-EW5SYO6L.js +1 -0
- package/dist/esm/chunks/chunk-HJY2JSNB.js +1 -0
- package/dist/esm/chunks/chunk-MQYB6BH4.js +1 -0
- package/dist/esm/chunks/{chunk-5Z5O3767.js → chunk-N3V45JPS.js} +1 -1
- package/dist/esm/chunks/{chunk-YLUULATY.js → chunk-RPMBCAGS.js} +1 -1
- package/dist/esm/chunks/{chunk-MPDWM2NN.js → chunk-VFNHIGCS.js} +1 -1
- package/dist/esm/chunks/{chunk-6OZJCAGZ.js → chunk-WT7RGGJU.js} +1 -1
- package/dist/esm/chunks/chunk-YN6LEBEN.js +1 -0
- package/dist/esm/chunks/chunk-Z6HS3H7K.js +1 -0
- package/dist/esm/chunks/{diagnose-3FEKRIEK.js → diagnose-XCEBQKBO.js} +1 -1
- package/dist/esm/chunks/extras-4HU3VSBQ.js +1 -0
- package/dist/esm/chunks/{markets-ui-FD6NI2OG.js → markets-ui-M4IQ62CT.js} +1 -1
- package/dist/esm/chunks/search-A5DS2IOS.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server.js +2 -2
- package/dist/tether.account-pages.js +13 -3
- package/dist/tether.account-pages.min.js +1 -1
- package/dist/tether.account.js +13 -3
- package/dist/tether.account.min.js +1 -1
- package/dist/tether.analytics.js +18 -3
- package/dist/tether.analytics.min.js +1 -1
- package/dist/tether.diagnose.js +18 -3
- package/dist/tether.diagnose.min.js +2 -2
- package/dist/tether.extras.js +19 -6
- package/dist/tether.extras.min.js +1 -1
- package/dist/tether.js +162 -112
- package/dist/tether.markets.js +18 -3
- package/dist/tether.markets.min.js +1 -1
- package/dist/tether.min.js +3 -3
- package/dist/tether.min.js.map +4 -4
- package/dist/tether.search.js +18 -3
- package/dist/tether.search.min.js +1 -1
- package/dist/types/server/src/shared/cart-id.d.ts +2 -0
- package/dist/types/src/cart/mutations.d.ts +6 -0
- package/dist/types/src/cart/store.d.ts +5 -2
- package/dist/types/src/cart.d.ts +2 -2
- package/dist/types/src/client.d.ts +53 -19
- package/dist/types/src/config.d.ts +6 -1
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/product-shape.d.ts +3 -1
- package/package.json +1 -2
- package/dist/esm/chunks/chunk-56FCLJJD.js +0 -1
- package/dist/esm/chunks/chunk-A5SYCVQM.js +0 -1
- package/dist/esm/chunks/chunk-BA4LQJJQ.js +0 -1
- package/dist/esm/chunks/chunk-C5JYQCWH.js +0 -1
- package/dist/esm/chunks/extras-6POFBNOP.js +0 -1
- package/dist/esm/chunks/search-UJ73YBQ5.js +0 -1
- package/src/account/addresses-view.ts +0 -58
- package/src/account/answers.ts +0 -79
- package/src/account/markup.ts +0 -36
- package/src/account/operations.ts +0 -145
- package/src/account/order-lines.ts +0 -75
- package/src/account/order-list.ts +0 -107
- package/src/account/order-page.ts +0 -137
- package/src/account/page-answers.ts +0 -317
- package/src/account/page-events.ts +0 -253
- package/src/account/server-client.ts +0 -183
- package/src/account/subscriptions-view.ts +0 -115
- package/src/account-api.ts +0 -98
- package/src/account-marks.ts +0 -35
- package/src/account-pages.ts +0 -81
- package/src/account.ts +0 -284
- package/src/amounts.ts +0 -64
- package/src/analytics-shopify.ts +0 -246
- package/src/analytics.ts +0 -315
- package/src/api-version.ts +0 -79
- package/src/astro.ts +0 -272
- package/src/cart/cart-shape.ts +0 -25
- package/src/cart/checkout.ts +0 -101
- package/src/cart/drawer.ts +0 -125
- package/src/cart/mutations.ts +0 -237
- package/src/cart/render.ts +0 -266
- package/src/cart/store.ts +0 -279
- package/src/cart.ts +0 -345
- package/src/client.ts +0 -391
- package/src/collection.ts +0 -175
- package/src/config-sections.ts +0 -284
- package/src/config.ts +0 -480
- package/src/controls/cart-controls.ts +0 -123
- package/src/controls/discount.ts +0 -75
- package/src/controls/extras.ts +0 -54
- package/src/controls/navigation.ts +0 -77
- package/src/diagnose-markup.ts +0 -298
- package/src/diagnose.ts +0 -294
- package/src/dom.ts +0 -268
- package/src/extras.ts +0 -136
- package/src/fragments.ts +0 -261
- package/src/globals.d.ts +0 -15
- package/src/images.ts +0 -91
- package/src/index.ts +0 -415
- package/src/initial.ts +0 -101
- package/src/lazy-iife.ts +0 -197
- package/src/lazy.ts +0 -42
- package/src/loader.ts +0 -363
- package/src/market-codes.ts +0 -6
- package/src/markets-ui.ts +0 -227
- package/src/markets.ts +0 -246
- package/src/markup.ts +0 -127
- package/src/mounting.ts +0 -264
- package/src/page-market.ts +0 -110
- package/src/part-integrity.ts +0 -7
- package/src/parts/account-pages.ts +0 -7
- package/src/parts/account.ts +0 -7
- package/src/parts/analytics.ts +0 -7
- package/src/parts/diagnose.ts +0 -7
- package/src/parts/extras.ts +0 -7
- package/src/parts/markets.ts +0 -7
- package/src/parts/search.ts +0 -7
- package/src/presets/barba.ts +0 -194
- package/src/product-events.ts +0 -115
- package/src/product-render.ts +0 -218
- package/src/product-shape.ts +0 -49
- package/src/product-state.ts +0 -318
- package/src/product.ts +0 -308
- package/src/repeaters.ts +0 -161
- package/src/search.ts +0 -305
- package/src/selling-plans.ts +0 -145
- package/src/server.ts +0 -211
- package/src/shopify-values.ts +0 -91
- package/src/status.ts +0 -106
- package/src/storage.ts +0 -34
- package/src/store-html.ts +0 -359
- package/src/storefront/catalog.ts +0 -196
- package/src/storefront/json-ld.ts +0 -144
- package/src/variant-render.ts +0 -139
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* schema.org data for search engines (Google's product rich results): a `Product`, or a `ProductGroup` with one
|
|
3
|
-
* `Product` per variant, each with its price, currency, stock, sku, image and `?variant=` link. Products that are only
|
|
4
|
-
* sold on a subscription are priced at their first plan.
|
|
5
|
-
*/
|
|
6
|
-
import { allPlans, allocationFor, planPrice } from '../selling-plans.ts';
|
|
7
|
-
import { productUrl } from '../shopify-values.ts';
|
|
8
|
-
import type { Product, ProductVariant } from '../fragments.ts';
|
|
9
|
-
import type { Money } from '../shopify-values.ts';
|
|
10
|
-
|
|
11
|
-
export interface JsonLdOptions {
|
|
12
|
-
/** The product page's absolute URL; default from the storefront's `siteUrl`. */
|
|
13
|
-
url?: string;
|
|
14
|
-
/** Default the product's vendor. */
|
|
15
|
-
brand?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** Where the product pages are. */
|
|
19
|
-
interface JsonLdSite {
|
|
20
|
-
productPath: string;
|
|
21
|
-
siteUrl: string | undefined;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** The option names schema.org has a property for: a `ProductGroup` varies by them. */
|
|
25
|
-
const VARIES_BY: Readonly<Record<string, string>> = {
|
|
26
|
-
size: 'https://schema.org/size',
|
|
27
|
-
color: 'https://schema.org/color',
|
|
28
|
-
colour: 'https://schema.org/color',
|
|
29
|
-
material: 'https://schema.org/material',
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Text for a `<script>` tag: `<` is escaped so product text can never close the tag, and U+2028 / U+2029 so older
|
|
34
|
-
* JavaScript parsers read it.
|
|
35
|
-
*/
|
|
36
|
-
export const scriptJson = (value: unknown): string =>
|
|
37
|
-
JSON.stringify(value)
|
|
38
|
-
.replace(/</g, '\\u003c')
|
|
39
|
-
.replace(/\u2028/g, '\\u2028')
|
|
40
|
-
.replace(/\u2029/g, '\\u2029');
|
|
41
|
-
|
|
42
|
-
/** @returns `value` without its `undefined` fields, nested ones too. */
|
|
43
|
-
function withoutUndefined(value: Record<string, unknown>): Record<string, unknown> {
|
|
44
|
-
const copy: unknown = JSON.parse(JSON.stringify(value));
|
|
45
|
-
// The JSON of an object is an object.
|
|
46
|
-
return copy as Record<string, unknown>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const numericId = (gid: string) => gid.split('/').pop() ?? gid;
|
|
50
|
-
|
|
51
|
-
/** @returns The schema.org availability. */
|
|
52
|
-
function availability(variant: ProductVariant): string {
|
|
53
|
-
if (!variant.availableForSale) return 'https://schema.org/OutOfStock';
|
|
54
|
-
return variant.currentlyNotInStock ? 'https://schema.org/BackOrder' : 'https://schema.org/InStock';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** @returns The variant's price, or its first plan's for a product sold only on a subscription. */
|
|
58
|
-
function offeredPrice(product: Product, variant: ProductVariant): Money {
|
|
59
|
-
if (!product.requiresSellingPlan) return variant.price;
|
|
60
|
-
const plan = allPlans(product).find((candidate) => allocationFor(variant, candidate.id));
|
|
61
|
-
return (plan && planPrice(variant, plan.id)) ?? variant.price;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function offer(product: Product, variant: ProductVariant, pageUrl: string | undefined) {
|
|
65
|
-
const price = offeredPrice(product, variant);
|
|
66
|
-
const separator = pageUrl?.includes('?') ? '&' : '?';
|
|
67
|
-
return {
|
|
68
|
-
'@type': 'Offer',
|
|
69
|
-
price: price.amount,
|
|
70
|
-
priceCurrency: price.currencyCode,
|
|
71
|
-
availability: availability(variant),
|
|
72
|
-
url: pageUrl ? `${pageUrl}${separator}variant=${numericId(variant.id)}` : undefined,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function variantProduct(
|
|
77
|
-
product: Product,
|
|
78
|
-
variant: ProductVariant,
|
|
79
|
-
pageUrl: string | undefined,
|
|
80
|
-
images: readonly string[],
|
|
81
|
-
) {
|
|
82
|
-
// schema.org property name → the variant's value.
|
|
83
|
-
const properties = variant.selectedOptions.flatMap((option): [string, string][] => {
|
|
84
|
-
const property = VARIES_BY[option.name.toLowerCase()];
|
|
85
|
-
return property ? [[property.split('/').pop() ?? property, option.value]] : [];
|
|
86
|
-
});
|
|
87
|
-
return {
|
|
88
|
-
'@type': 'Product',
|
|
89
|
-
name: `${product.title} - ${variant.title}`,
|
|
90
|
-
sku: variant.sku || undefined,
|
|
91
|
-
image: variant.image?.url || images[0],
|
|
92
|
-
...Object.fromEntries(properties),
|
|
93
|
-
offers: offer(product, variant, pageUrl),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function pageUrlOf(product: Product, { url }: JsonLdOptions, site: JsonLdSite): string | undefined {
|
|
98
|
-
if (url) return url;
|
|
99
|
-
const path = productUrl(site.productPath, product.handle, product.id);
|
|
100
|
-
if (!site.siteUrl || !path) return undefined;
|
|
101
|
-
return new URL(path, site.siteUrl).toString();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** @returns The schema.org object, `null` without a product. */
|
|
105
|
-
export function jsonLdData(
|
|
106
|
-
product: Product | null | undefined,
|
|
107
|
-
options: JsonLdOptions,
|
|
108
|
-
site: JsonLdSite,
|
|
109
|
-
): Record<string, unknown> | null {
|
|
110
|
-
if (!product) return null;
|
|
111
|
-
const pageUrl = pageUrlOf(product, options, site);
|
|
112
|
-
const images = product.images.nodes.map((image) => image.url).filter(Boolean);
|
|
113
|
-
const brandName = options.brand || product.vendor;
|
|
114
|
-
const brand = brandName ? { '@type': 'Brand', name: brandName } : undefined;
|
|
115
|
-
const description = product.description.trim() || undefined;
|
|
116
|
-
const variants = product.variants.nodes;
|
|
117
|
-
if (variants.length <= 1) {
|
|
118
|
-
const [variant] = variants;
|
|
119
|
-
return withoutUndefined({
|
|
120
|
-
'@context': 'https://schema.org',
|
|
121
|
-
'@type': 'Product',
|
|
122
|
-
name: product.title,
|
|
123
|
-
description,
|
|
124
|
-
url: pageUrl,
|
|
125
|
-
image: images,
|
|
126
|
-
sku: variant?.sku || undefined,
|
|
127
|
-
brand,
|
|
128
|
-
offers: variant ? offer(product, variant, pageUrl) : undefined,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
const variesBy = product.options.map((option) => VARIES_BY[option.name.toLowerCase()]).filter(Boolean);
|
|
132
|
-
return withoutUndefined({
|
|
133
|
-
'@context': 'https://schema.org',
|
|
134
|
-
'@type': 'ProductGroup',
|
|
135
|
-
name: product.title,
|
|
136
|
-
description,
|
|
137
|
-
url: pageUrl,
|
|
138
|
-
productGroupID: numericId(product.id),
|
|
139
|
-
image: images,
|
|
140
|
-
brand,
|
|
141
|
-
variesBy: [...new Set(variesBy)],
|
|
142
|
-
hasVariant: variants.map((variant) => variantProduct(product, variant, pageUrl, images)),
|
|
143
|
-
});
|
|
144
|
-
}
|
package/src/variant-render.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The DOM writes of a product scope that follow the visitor's choice, on every change: `product-state.ts`'s view as
|
|
3
|
-
* text, selected and unavailable states, `tether-show` conditions and the add-to-cart buttons.
|
|
4
|
-
*/
|
|
5
|
-
import { attr, sel, get, qsa, formatMoney, formatPercent, setText, setImage, setSelected, show } from './dom.ts';
|
|
6
|
-
import { STATUS_KEYS, ownedBy } from './status.ts';
|
|
7
|
-
import { allocationFor } from './selling-plans.ts';
|
|
8
|
-
import { isValueAvailable, planBindTexts, variantBindTexts } from './product-state.ts';
|
|
9
|
-
import { isSelect, selectsIn } from './product-render.ts';
|
|
10
|
-
import type { Formatters, ProductView } from './product-state.ts';
|
|
11
|
-
import type { RenderScope } from './product-render.ts';
|
|
12
|
-
|
|
13
|
-
const FORMAT: Formatters = { money: formatMoney, percent: formatPercent };
|
|
14
|
-
|
|
15
|
-
const isInput = (el: Element): el is HTMLInputElement => el.tagName === 'INPUT';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* The element of an add-to-cart button that holds its label, with the label as written kept in
|
|
19
|
-
* `data-tether-label`, so mode-dependent texts (`tether-subscribe-text`, `tether-soldout-text`) can be undone.
|
|
20
|
-
*/
|
|
21
|
-
export function addButtonLabel(button: HTMLElement): { label: HTMLElement; original: string } {
|
|
22
|
-
const label = qsa(button, sel('add-label'))[0] ?? button;
|
|
23
|
-
const original = label.dataset['tetherLabel'] ?? (isInput(label) ? label.value : label.textContent);
|
|
24
|
-
label.dataset['tetherLabel'] = original;
|
|
25
|
-
return { label, original };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function renderOptionStates(scope: RenderScope, view: ProductView): void {
|
|
29
|
-
const { product } = scope;
|
|
30
|
-
const selectedValue = (authored: string | null) => view.selected[scope.optName(authored)] ?? '';
|
|
31
|
-
scope.$(sel('option-selected')).forEach((el) => {
|
|
32
|
-
setText(el, selectedValue(get(el, 'option-selected')));
|
|
33
|
-
});
|
|
34
|
-
scope.$(sel('option-list')).forEach((container) => {
|
|
35
|
-
const name = scope.optName(get(container, 'option-list'));
|
|
36
|
-
qsa(container, sel('option-value')).forEach((node) => {
|
|
37
|
-
const value = get(node, 'option-value') ?? '';
|
|
38
|
-
setSelected(node, view.selected[name] === value);
|
|
39
|
-
const unavailable = !isValueAvailable(product, view.selected, name, value);
|
|
40
|
-
node.classList.toggle('is-unavailable', unavailable);
|
|
41
|
-
node.setAttribute('data-unavailable', unavailable ? 'true' : 'false');
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
selectsIn(scope, sel('option')).forEach((select) => {
|
|
45
|
-
select.value = selectedValue(get(select, 'option'));
|
|
46
|
-
});
|
|
47
|
-
selectsIn(scope, sel('variant-select')).forEach((select) => {
|
|
48
|
-
select.value = view.variant.id;
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* The purchase toggles and the plan list and select.
|
|
54
|
-
*/
|
|
55
|
-
function renderPurchaseStates(scope: RenderScope, view: ProductView): void {
|
|
56
|
-
const { variant, purchase, line } = view;
|
|
57
|
-
scope.$(sel('purchase')).forEach((el) => {
|
|
58
|
-
if (isSelect(el)) {
|
|
59
|
-
el.value = purchase.kind;
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const mode = get(el, 'purchase');
|
|
63
|
-
setSelected(el, mode === purchase.kind);
|
|
64
|
-
const unavailable = mode === 'subscription' ? !view.subscriptionAvailable : scope.product.requiresSellingPlan;
|
|
65
|
-
el.classList.toggle('is-unavailable', unavailable);
|
|
66
|
-
});
|
|
67
|
-
scope.$(sel('plan-value')).forEach((node) => {
|
|
68
|
-
const planId = get(node, 'plan-value') ?? '';
|
|
69
|
-
setSelected(node, line.kind === 'subscription' && planId === line.planId);
|
|
70
|
-
node.classList.toggle('is-unavailable', !allocationFor(variant, planId));
|
|
71
|
-
const plan = scope.plans.find((candidate) => candidate.id === planId);
|
|
72
|
-
const texts = planBindTexts(variant, planId, plan, FORMAT);
|
|
73
|
-
qsa(node, sel('plan-bind')).forEach((el) => {
|
|
74
|
-
const text = texts.get(get(el, 'plan-bind') ?? '');
|
|
75
|
-
if (text) setText(el, text());
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
selectsIn(scope, sel('plan')).forEach((select) => {
|
|
79
|
-
select.value = line.kind === 'subscription' ? line.planId : '';
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* The `tether-show` conditions, with the scope's own status: a product scope that renders is ready.
|
|
85
|
-
*/
|
|
86
|
-
function renderConditions(scope: RenderScope, view: ProductView): void {
|
|
87
|
-
const conditions = new Map<string, boolean>(Object.entries(view.show));
|
|
88
|
-
STATUS_KEYS.forEach((status) => conditions.set(status, status === 'ready'));
|
|
89
|
-
scope.$(sel('show')).forEach((el) => {
|
|
90
|
-
const key = get(el, 'show') ?? '';
|
|
91
|
-
const visible = conditions.get(key);
|
|
92
|
-
if (visible === undefined) return;
|
|
93
|
-
// State blocks of a list nested in this product belong to that list.
|
|
94
|
-
if (STATUS_KEYS.some((status) => status === key) && !ownedBy(el, scope.root)) return;
|
|
95
|
-
show(el, visible);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function renderAddButtons(scope: RenderScope, view: ProductView): void {
|
|
100
|
-
const disabled = !view.variant.availableForSale;
|
|
101
|
-
scope.$(sel('add-to-cart')).forEach((button) => {
|
|
102
|
-
button.classList.toggle('is-disabled', disabled);
|
|
103
|
-
button.setAttribute('aria-disabled', String(disabled));
|
|
104
|
-
// A <button> or <input> is disabled; a link or div carries only aria-disabled.
|
|
105
|
-
if ('disabled' in button) button.disabled = disabled;
|
|
106
|
-
const soldOutText = get(button, 'soldout-text');
|
|
107
|
-
const subscribeText = get(button, 'subscribe-text');
|
|
108
|
-
if (!soldOutText && !subscribeText) return;
|
|
109
|
-
const { label, original } = addButtonLabel(button);
|
|
110
|
-
let text = original;
|
|
111
|
-
if (view.line.kind === 'subscription' && subscribeText) text = subscribeText;
|
|
112
|
-
if (disabled && soldOutText) text = soldOutText;
|
|
113
|
-
if (button.getAttribute('aria-busy') !== 'true') setText(label, text);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Writes what follows the variant and purchase.
|
|
119
|
-
*/
|
|
120
|
-
export function writeVariant(scope: RenderScope, view: ProductView): void {
|
|
121
|
-
const { variant } = view;
|
|
122
|
-
const { product } = scope;
|
|
123
|
-
const texts = variantBindTexts(view, FORMAT);
|
|
124
|
-
scope.$(sel('bind')).forEach((el) => {
|
|
125
|
-
const key = get(el, 'bind') ?? '';
|
|
126
|
-
if (key === 'variant-image') {
|
|
127
|
-
setImage(el, variant.image?.url || product.featuredImage?.url, variant.image?.altText || product.title);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const text = texts.get(key);
|
|
131
|
-
if (text) setText(el, text());
|
|
132
|
-
});
|
|
133
|
-
renderOptionStates(scope, view);
|
|
134
|
-
renderPurchaseStates(scope, view);
|
|
135
|
-
renderConditions(scope, view);
|
|
136
|
-
scope.root.classList.toggle('is-subscription', view.line.kind === 'subscription');
|
|
137
|
-
scope.root.setAttribute(attr('purchase-mode'), view.line.kind);
|
|
138
|
-
renderAddButtons(scope, view);
|
|
139
|
-
}
|