@teleporthq/teleport-shared 0.43.67 → 0.43.69
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/__tests__/_helpers/embed-runtime-emitter.ts +197 -0
- package/__tests__/utils/discount-engine.ts +1548 -0
- package/__tests__/utils/product-options.ts +2458 -0
- package/__tests__/utils/rich-text-embeds-runtime-module.ts +34 -0
- package/__tests__/utils/subscription-access.ts +37 -0
- package/dist/cjs/index.d.ts +9 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +17 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils/cart-currency.d.ts +27 -0
- package/dist/cjs/utils/cart-currency.d.ts.map +1 -0
- package/dist/cjs/utils/cart-currency.js +31 -0
- package/dist/cjs/utils/cart-currency.js.map +1 -0
- package/dist/cjs/utils/cart-line-pricing.d.ts +25 -0
- package/dist/cjs/utils/cart-line-pricing.d.ts.map +1 -0
- package/dist/cjs/utils/cart-line-pricing.js +29 -0
- package/dist/cjs/utils/cart-line-pricing.js.map +1 -0
- package/dist/cjs/utils/discount-engine.d.ts +74 -0
- package/dist/cjs/utils/discount-engine.d.ts.map +1 -0
- package/dist/cjs/utils/discount-engine.js +435 -0
- package/dist/cjs/utils/discount-engine.js.map +1 -0
- package/dist/cjs/utils/product-options.d.ts +25 -0
- package/dist/cjs/utils/product-options.d.ts.map +1 -0
- package/dist/cjs/utils/product-options.js +1155 -0
- package/dist/cjs/utils/product-options.js.map +1 -0
- package/dist/cjs/utils/rich-text-embeds-codegen.d.ts +13 -0
- package/dist/cjs/utils/rich-text-embeds-codegen.d.ts.map +1 -1
- package/dist/cjs/utils/rich-text-embeds-codegen.js +15 -104
- package/dist/cjs/utils/rich-text-embeds-codegen.js.map +1 -1
- package/dist/cjs/utils/rich-text-embeds-runtime-source.d.ts +2 -0
- package/dist/cjs/utils/rich-text-embeds-runtime-source.d.ts.map +1 -0
- package/dist/cjs/utils/rich-text-embeds-runtime-source.js +409 -0
- package/dist/cjs/utils/rich-text-embeds-runtime-source.js.map +1 -0
- package/dist/cjs/utils/session-cookie-resolver.d.ts +85 -0
- package/dist/cjs/utils/session-cookie-resolver.d.ts.map +1 -0
- package/dist/cjs/utils/session-cookie-resolver.js +108 -0
- package/dist/cjs/utils/session-cookie-resolver.js.map +1 -0
- package/dist/cjs/utils/subscription-access.d.ts +36 -0
- package/dist/cjs/utils/subscription-access.d.ts.map +1 -0
- package/dist/cjs/utils/subscription-access.js +61 -0
- package/dist/cjs/utils/subscription-access.js.map +1 -0
- package/dist/cjs/utils/table-access.d.ts +114 -0
- package/dist/cjs/utils/table-access.d.ts.map +1 -0
- package/dist/cjs/utils/table-access.js +238 -0
- package/dist/cjs/utils/table-access.js.map +1 -0
- package/dist/cjs/utils/web-push.d.ts +43 -0
- package/dist/cjs/utils/web-push.d.ts.map +1 -0
- package/dist/cjs/utils/web-push.js +62 -0
- package/dist/cjs/utils/web-push.js.map +1 -0
- package/dist/esm/index.d.ts +9 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +9 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils/cart-currency.d.ts +27 -0
- package/dist/esm/utils/cart-currency.d.ts.map +1 -0
- package/dist/esm/utils/cart-currency.js +27 -0
- package/dist/esm/utils/cart-currency.js.map +1 -0
- package/dist/esm/utils/cart-line-pricing.d.ts +25 -0
- package/dist/esm/utils/cart-line-pricing.d.ts.map +1 -0
- package/dist/esm/utils/cart-line-pricing.js +25 -0
- package/dist/esm/utils/cart-line-pricing.js.map +1 -0
- package/dist/esm/utils/discount-engine.d.ts +74 -0
- package/dist/esm/utils/discount-engine.d.ts.map +1 -0
- package/dist/esm/utils/discount-engine.js +431 -0
- package/dist/esm/utils/discount-engine.js.map +1 -0
- package/dist/esm/utils/product-options.d.ts +25 -0
- package/dist/esm/utils/product-options.d.ts.map +1 -0
- package/dist/esm/utils/product-options.js +1151 -0
- package/dist/esm/utils/product-options.js.map +1 -0
- package/dist/esm/utils/rich-text-embeds-codegen.d.ts +13 -0
- package/dist/esm/utils/rich-text-embeds-codegen.d.ts.map +1 -1
- package/dist/esm/utils/rich-text-embeds-codegen.js +16 -105
- package/dist/esm/utils/rich-text-embeds-codegen.js.map +1 -1
- package/dist/esm/utils/rich-text-embeds-runtime-source.d.ts +2 -0
- package/dist/esm/utils/rich-text-embeds-runtime-source.d.ts.map +1 -0
- package/dist/esm/utils/rich-text-embeds-runtime-source.js +406 -0
- package/dist/esm/utils/rich-text-embeds-runtime-source.js.map +1 -0
- package/dist/esm/utils/session-cookie-resolver.d.ts +85 -0
- package/dist/esm/utils/session-cookie-resolver.d.ts.map +1 -0
- package/dist/esm/utils/session-cookie-resolver.js +103 -0
- package/dist/esm/utils/session-cookie-resolver.js.map +1 -0
- package/dist/esm/utils/subscription-access.d.ts +36 -0
- package/dist/esm/utils/subscription-access.d.ts.map +1 -0
- package/dist/esm/utils/subscription-access.js +57 -0
- package/dist/esm/utils/subscription-access.js.map +1 -0
- package/dist/esm/utils/table-access.d.ts +114 -0
- package/dist/esm/utils/table-access.d.ts.map +1 -0
- package/dist/esm/utils/table-access.js +233 -0
- package/dist/esm/utils/table-access.js.map +1 -0
- package/dist/esm/utils/web-push.d.ts +43 -0
- package/dist/esm/utils/web-push.d.ts.map +1 -0
- package/dist/esm/utils/web-push.js +59 -0
- package/dist/esm/utils/web-push.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +16 -0
- package/src/utils/cart-currency.ts +76 -0
- package/src/utils/cart-line-pricing.ts +151 -0
- package/src/utils/discount-engine.ts +437 -0
- package/src/utils/product-options.ts +1150 -0
- package/src/utils/rich-text-embeds-codegen.ts +16 -183
- package/src/utils/rich-text-embeds-runtime-source.ts +405 -0
- package/src/utils/session-cookie-resolver.ts +305 -0
- package/src/utils/subscription-access.ts +59 -0
- package/src/utils/table-access.ts +516 -0
- package/src/utils/web-push.ts +61 -0
|
@@ -0,0 +1,1155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateProductOptionsHelperCode = exports.PRODUCT_OPTIONS_HELPERS_CLOSING = exports.PRODUCT_OPTIONS_HELPERS_OPENING = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Product options as ES5 source, for generated runtime code that cannot import
|
|
6
|
+
* from this package: the data-source product transform, the storefront cart
|
|
7
|
+
* provider, and every workflow script that prices a configuration.
|
|
8
|
+
*
|
|
9
|
+
* ⚠️ THIRD MIRROR. The same rules exist in teleport-gui as
|
|
10
|
+
* `features/e-commerce/utils/product-options/` (the editor/canvas TypeScript)
|
|
11
|
+
* and `features/workflows/templates/builders/ecommerce/product-options-script.ts`
|
|
12
|
+
* (`PRODUCT_OPTIONS_HELPERS`, whose text this function returns verbatim). All
|
|
13
|
+
* three must agree to the cent, or the price on the product page, the price
|
|
14
|
+
* added to the cart and the price stored on the order will differ.
|
|
15
|
+
* `__tests__/utils/product-options.ts` runs this copy over a fixture table that
|
|
16
|
+
* is byte-identical with the GUI's parity spec.
|
|
17
|
+
*
|
|
18
|
+
* The block: `var` / `function` only, names prefixed `__po`; no backticks, no
|
|
19
|
+
* dollar-brace, no backslash, never `params` followed by a dot; no `__po`
|
|
20
|
+
* function with exactly two parameters (the handler-entry resolver in
|
|
21
|
+
* `teleport-plugin-next-workflows/src/nodes/types.ts` picks the first
|
|
22
|
+
* two-parameter declaration); wrapped in the sentinel comments below so an
|
|
23
|
+
* export-time refresh can replace it.
|
|
24
|
+
*/
|
|
25
|
+
exports.PRODUCT_OPTIONS_HELPERS_OPENING = '/* tq:po-helpers:start v1 */';
|
|
26
|
+
exports.PRODUCT_OPTIONS_HELPERS_CLOSING = '/* tq:po-helpers:end */';
|
|
27
|
+
var generateProductOptionsHelperCode = function () {
|
|
28
|
+
return [
|
|
29
|
+
exports.PRODUCT_OPTIONS_HELPERS_OPENING,
|
|
30
|
+
'var __poLimits = { groups: 30, values: 60, rules: 5, priceOverrides: 12, labelChars: 120, text: 500, longText: 2000, configurationChars: 8000, configurationLabelChars: 500, optionGroupsChars: 32000, uploadBytes: 4194304, maxAmount: 1000000000 };',
|
|
31
|
+
'var __poTypes = ["choice", "multi-choice", "text", "long-text", "number", "toggle", "upload"];',
|
|
32
|
+
// Type names an AI or an import commonly gives, as parse reads them (matched on the slug). Same table as OPTION_TYPE_ALIASES.
|
|
33
|
+
'var __poTypeAliases = [["select", "choice"], ["dropdown", "choice"], ["radio", "choice"], ["single-choice", "choice"], ["pick-one", "choice"], ["swatches", "choice"], ["multiple-choice", "multi-choice"], ["multi-select", "multi-choice"], ["multiselect", "multi-choice"], ["multichoice", "multi-choice"], ["checkboxes", "multi-choice"], ["pick-several", "multi-choice"], ["string", "text"], ["short-text", "text"], ["textarea", "long-text"], ["longtext", "long-text"], ["paragraph", "long-text"], ["integer", "number"], ["quantity", "number"], ["numeric", "number"], ["boolean", "toggle"], ["switch", "toggle"], ["yes-no", "toggle"], ["yes-or-no", "toggle"], ["file", "upload"], ["file-upload", "upload"], ["image", "upload"], ["photo", "upload"]];',
|
|
34
|
+
// What an upload group lets through (never SVG). Same table as PRODUCT_OPTION_UPLOAD_MIME.
|
|
35
|
+
'var __poUploadMime = { image: ["image/jpeg", "image/png", "image/webp", "image/gif"], pdf: ["application/pdf"], any: ["image/jpeg", "image/png", "image/webp", "image/gif", "application/pdf"] };',
|
|
36
|
+
'var __poValueTypes = ["choice", "multi-choice"];',
|
|
37
|
+
'var __poPricedTypes = ["text", "long-text", "number", "toggle", "upload"];',
|
|
38
|
+
'var __poSelectableTypes = ["choice", "multi-choice", "toggle"];',
|
|
39
|
+
'var __poDisplays = ["buttons", "swatches", "cards"];',
|
|
40
|
+
'var __poAccepts = ["image", "pdf", "any"];',
|
|
41
|
+
'var __poOperators = ["is", "is-not", "is-set", "is-not-set"];',
|
|
42
|
+
'var __poWarningCodes = ["CONFIGURATION_TOO_LONG", "OPTION_GROUPS_TOO_LARGE"];',
|
|
43
|
+
// The validator's refusals; `{option}` and `{source}` are filled in. Same text as PRODUCT_OPTION_MESSAGES.
|
|
44
|
+
'var __poMessages = {',
|
|
45
|
+
' TOO_MANY_GROUPS: "A product can have at most 30 options.",',
|
|
46
|
+
' GROUP_LABEL_REQUIRED: "{option} needs a name.",',
|
|
47
|
+
' GROUP_LABEL_TOO_LONG: "The name of “{option}” is longer than 120 characters.",',
|
|
48
|
+
' DUPLICATE_GROUP_KEY: "“{option}” uses the same internal key as an earlier option.",',
|
|
49
|
+
' CHOICE_NEEDS_VALUE: "“{option}” needs at least one choice.",',
|
|
50
|
+
' TOO_MANY_VALUES: "“{option}” can have at most 60 choices.",',
|
|
51
|
+
' VALUE_LABEL_REQUIRED: "Every choice of “{option}” needs a name.",',
|
|
52
|
+
' VALUE_LABEL_TOO_LONG: "A choice of “{option}” is longer than 120 characters.",',
|
|
53
|
+
' DUPLICATE_VALUE_KEY: "Two choices of “{option}” use the same internal key.",',
|
|
54
|
+
' VALUE_LABEL_DUPLICATE: "Two choices of “{option}” have the same name.",',
|
|
55
|
+
' MULTI_MIN_MAX: "“{option}”: the minimum number of picks is more than the maximum.",',
|
|
56
|
+
' MULTI_MAX_TOO_LOW: "“{option}”: allow at least one pick, or leave the maximum empty for no limit.",',
|
|
57
|
+
' MULTI_TOO_FEW_VALUES: "“{option}” asks for more picks than it has choices.",',
|
|
58
|
+
' MULTI_DEFAULTS_TOO_MANY: "“{option}” pre-selects more choices than shoppers may pick. Pre-select fewer, or raise the maximum.",',
|
|
59
|
+
' TEXT_MAX_LENGTH: "“{option}”: the character limit must be between 1 and 500.",',
|
|
60
|
+
' LONG_TEXT_MAX_LENGTH: "“{option}”: the character limit must be between 1 and 2000.",',
|
|
61
|
+
' NUMBER_MIN_MAX: "“{option}”: the minimum is more than the maximum.",',
|
|
62
|
+
' NUMBER_STEP: "“{option}”: the step must be more than 0.",',
|
|
63
|
+
' NUMBER_DEFAULT_RANGE: "“{option}”: the starting value must be between the minimum and the maximum.",',
|
|
64
|
+
' NUMBER_DEFAULT_STEP: "“{option}”: the starting value must be a whole number of steps from the minimum.",',
|
|
65
|
+
' PRICE_AMOUNT_INVALID: "Prices on “{option}” must be between 0 and 1,000,000,000.",',
|
|
66
|
+
' PRICE_PERCENT_RANGE: "A percentage on “{option}” must be between 0 and 1000.",',
|
|
67
|
+
' PRICE_PER_UNIT_NUMBER_ONLY: "Only a number option can be priced per unit, so “{option}” cannot.",',
|
|
68
|
+
' PRICE_TOO_MANY_OVERRIDES: "“{option}” can have at most 12 prices that depend on other options.",',
|
|
69
|
+
' PRICE_SOURCE_MISSING: "A price on “{option}” depends on an option that no longer exists.",',
|
|
70
|
+
' PRICE_SOURCE_LATER: "A price on “{option}” depends on “{source}”, which comes after it. Move “{source}” above “{option}”.",',
|
|
71
|
+
' PRICE_SOURCE_TYPE: "A price on “{option}” can only depend on a pick-one, pick-several or yes-or-no option.",',
|
|
72
|
+
' PRICE_SOURCE_VALUES: "A price on “{option}” depends on a choice of “{source}” that no longer exists.",',
|
|
73
|
+
' VISIBILITY_TOO_MANY_RULES: "“{option}” can have at most 5 rules for when it is shown.",',
|
|
74
|
+
' VISIBILITY_SOURCE_MISSING: "“{option}” is shown depending on an option that no longer exists.",',
|
|
75
|
+
' VISIBILITY_SOURCE_LATER: "“{option}” is shown depending on “{source}”, which comes after it. Move “{source}” above “{option}”.",',
|
|
76
|
+
' VISIBILITY_SOURCE_TYPE: "“{option}” can only be shown depending on a pick-one, pick-several or yes-or-no option.",',
|
|
77
|
+
' VISIBILITY_SOURCE_VALUES: "“{option}” is shown depending on a choice of “{source}” that no longer exists.",',
|
|
78
|
+
' GIFT_CARD_OPTIONS_PRICE: "Gift cards can have options, but not prices on them. Set every option to no extra charge.",',
|
|
79
|
+
' RECURRING_OPTIONS_PRICE: "Subscription products can have options, but not prices on them. Set every option to no extra charge.",',
|
|
80
|
+
' CONFIGURATION_TOO_LONG: "Filled in to their limits, these options could exceed 8000 characters and be refused at checkout. Use fewer options, or lower the character limits of the text options.",',
|
|
81
|
+
' OPTION_GROUPS_TOO_LARGE: "These options take more than 32000 characters to save. Use fewer choices or shorter descriptions.",',
|
|
82
|
+
' OPTIONS_UNREADABLE: "The options could not be read. Send them as a list of options, each with a name and a type.",',
|
|
83
|
+
' OPTION_TYPE_UNKNOWN: "“{option}” has a type that does not exist. Use pick one, pick several, short text, long text, number, yes or no, or file upload.",',
|
|
84
|
+
' VALUE_UNREADABLE: "A choice of “{option}” could not be read. Give every choice a name.",',
|
|
85
|
+
' PRICE_UNREADABLE: "A price on “{option}” could not be read. Use a fixed amount or a percentage (an amount per unit only on a number option), and put the prices of a pick-one or pick-several option on its choices.",',
|
|
86
|
+
' VISIBILITY_RULE_UNREADABLE: "A rule for when “{option}” is shown could not be read. Use is, is not, is set or is not set on an earlier option."',
|
|
87
|
+
'};',
|
|
88
|
+
// Primitive readers. Every value arrives from JSON, a driver or the DOM, so nothing is trusted.
|
|
89
|
+
'function __poRound2(n) { return Math.round(n * 100) / 100; }',
|
|
90
|
+
'function __poIsObject(v) { return v !== null && typeof v === "object" && !Array.isArray(v); }',
|
|
91
|
+
'function __poFinite(v) {',
|
|
92
|
+
' if (typeof v === "number") { return isFinite(v) ? v : undefined; }',
|
|
93
|
+
' if (typeof v === "string" && v.trim() !== "") {',
|
|
94
|
+
' var parsed = Number(v.trim());',
|
|
95
|
+
' return isFinite(parsed) ? parsed : undefined;',
|
|
96
|
+
' }',
|
|
97
|
+
' return undefined;',
|
|
98
|
+
'}',
|
|
99
|
+
'function __poSafe(v) {',
|
|
100
|
+
' var parsed = __poFinite(v);',
|
|
101
|
+
' return parsed === undefined ? 0 : parsed;',
|
|
102
|
+
'}',
|
|
103
|
+
'function __poText(v) {',
|
|
104
|
+
' if (typeof v === "string") { return v; }',
|
|
105
|
+
' if (typeof v === "number" && isFinite(v)) { return String(v); }',
|
|
106
|
+
' return "";',
|
|
107
|
+
'}',
|
|
108
|
+
'function __poFlag(v) {',
|
|
109
|
+
' if (v === true || v === 1) { return true; }',
|
|
110
|
+
' if (typeof v === "string") {',
|
|
111
|
+
' var s = v.trim().toLowerCase();',
|
|
112
|
+
' return s === "true" || s === "t" || s === "1" || s === "yes" || s === "on";',
|
|
113
|
+
' }',
|
|
114
|
+
' return false;',
|
|
115
|
+
'}',
|
|
116
|
+
// Cuts to max UTF-16 units; a cut that would split a surrogate pair (55296-56319 = a high half) keeps one unit less.
|
|
117
|
+
'function __poClip(text, max, ellipsis) {',
|
|
118
|
+
' if (text.length <= max) { return text; }',
|
|
119
|
+
' var end = ellipsis ? max - 1 : max;',
|
|
120
|
+
' var last = end > 0 ? text.charCodeAt(end - 1) : 0;',
|
|
121
|
+
' if (last >= 55296 && last <= 56319) { end -= 1; }',
|
|
122
|
+
' return ellipsis ? text.slice(0, end) + "…" : text.slice(0, end);',
|
|
123
|
+
'}',
|
|
124
|
+
// Collapses runs of spaces, control characters (<= 32, 127-159) and U+2028 / U+2029 into one space, trimming the ends (no regex: no backslashes allowed).
|
|
125
|
+
'function __poOneLine(text) {',
|
|
126
|
+
' var out = "";',
|
|
127
|
+
' var pending = false;',
|
|
128
|
+
' for (var i = 0; i < text.length; i++) {',
|
|
129
|
+
' var code = text.charCodeAt(i);',
|
|
130
|
+
' if (code <= 32 || (code >= 127 && code <= 159) || code === 8232 || code === 8233) { pending = out.length > 0; continue; }',
|
|
131
|
+
' if (pending) { out += " "; pending = false; }',
|
|
132
|
+
' out += text.charAt(i);',
|
|
133
|
+
' }',
|
|
134
|
+
' return out;',
|
|
135
|
+
'}',
|
|
136
|
+
'function __poSlug(text) {',
|
|
137
|
+
' return String(text).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 200);',
|
|
138
|
+
'}',
|
|
139
|
+
'function __poWhole(v) {',
|
|
140
|
+
' var parsed = __poFinite(v);',
|
|
141
|
+
' return parsed === undefined ? undefined : Math.max(0, Math.floor(parsed));',
|
|
142
|
+
'}',
|
|
143
|
+
'function __poWith(base, field, value) {',
|
|
144
|
+
' var out = {};',
|
|
145
|
+
' for (var k in base) { if (Object.prototype.hasOwnProperty.call(base, k)) { out[k] = base[k]; } }',
|
|
146
|
+
' out[field] = value;',
|
|
147
|
+
' return out;',
|
|
148
|
+
'}',
|
|
149
|
+
// Keys: the slug of the label (or the fallback), then -2, -3, ... until free.
|
|
150
|
+
'function __poMintKey(label, taken, fallback) {',
|
|
151
|
+
' var list = Array.isArray(taken) ? taken : [];',
|
|
152
|
+
' var base = __poSlug(typeof label === "string" ? label : "") || (fallback || "option");',
|
|
153
|
+
' if (list.indexOf(base) === -1) { return base; }',
|
|
154
|
+
' var suffix = 2;',
|
|
155
|
+
' while (list.indexOf(base + "-" + suffix) !== -1) { suffix++; }',
|
|
156
|
+
' return base + "-" + suffix;',
|
|
157
|
+
'}',
|
|
158
|
+
'function __poSourceValueKeys(group) {',
|
|
159
|
+
' if (group.type === "toggle") { return ["on"]; }',
|
|
160
|
+
' var values = Array.isArray(group.values) ? group.values : [];',
|
|
161
|
+
' var out = [];',
|
|
162
|
+
' for (var i = 0; i < values.length; i++) { if (__poIsObject(values[i])) { out.push(values[i].key); } }',
|
|
163
|
+
' return out;',
|
|
164
|
+
'}',
|
|
165
|
+
'function __poFindGroup(groups, key, types) {',
|
|
166
|
+
' for (var i = 0; i < groups.length; i++) {',
|
|
167
|
+
' if (groups[i].key === key) { return !types || types.indexOf(groups[i].type) !== -1 ? groups[i] : null; }',
|
|
168
|
+
' }',
|
|
169
|
+
' return null;',
|
|
170
|
+
'}',
|
|
171
|
+
// Parsing option_groups: total, clamped, keys minted, rules kept only when they point at EARLIER selectable groups.
|
|
172
|
+
'function __poAmount(n) { return isFinite(n) && n > 0 ? Math.min(__poLimits.maxAmount, n) : 0; }',
|
|
173
|
+
'function __poParseRule(raw) {',
|
|
174
|
+
' if (typeof raw === "number") { return { mode: "fixed", amount: __poAmount(raw) }; }',
|
|
175
|
+
' if (typeof raw === "string") {',
|
|
176
|
+
' var bare = __poFinite(raw);',
|
|
177
|
+
' return bare === undefined ? { mode: "none" } : { mode: "fixed", amount: __poAmount(bare) };',
|
|
178
|
+
' }',
|
|
179
|
+
' if (!__poIsObject(raw)) { return { mode: "none" }; }',
|
|
180
|
+
' if (raw.mode === "fixed") { return { mode: "fixed", amount: __poAmount(__poSafe(raw.amount)) }; }',
|
|
181
|
+
' if (raw.mode === "percent") { return { mode: "percent", percent: Math.min(1000, Math.max(0, __poSafe(raw.percent))) }; }',
|
|
182
|
+
' if (raw.mode === "per-unit") { return { mode: "per-unit", amount: __poAmount(__poSafe(raw.amount)) }; }',
|
|
183
|
+
' return { mode: "none" };',
|
|
184
|
+
'}',
|
|
185
|
+
// The type a group means (readOptionGroupType), or null: exact, then its slug, then a synonym.
|
|
186
|
+
'function __poReadType(raw) {',
|
|
187
|
+
' var hasValues = Array.isArray(raw.values) && raw.values.length > 0;',
|
|
188
|
+
' if (__poTypes.indexOf(raw.type) !== -1) { return raw.type; }',
|
|
189
|
+
' var slug = __poSlug(__poText(raw.type));',
|
|
190
|
+
' if (slug === "") { return null; }',
|
|
191
|
+
' if (__poTypes.indexOf(slug) !== -1) { return slug; }',
|
|
192
|
+
' if (slug === "checkbox") { return hasValues ? "multi-choice" : "toggle"; }',
|
|
193
|
+
' for (var i = 0; i < __poTypeAliases.length; i++) {',
|
|
194
|
+
' if (__poTypeAliases[i][0] === slug) { return __poTypeAliases[i][1] === "upload" && hasValues ? "choice" : __poTypeAliases[i][1]; }',
|
|
195
|
+
' }',
|
|
196
|
+
' return null;',
|
|
197
|
+
'}',
|
|
198
|
+
'function __poUnitless(rule) {',
|
|
199
|
+
' return rule.mode === "per-unit" ? { mode: "fixed", amount: rule.amount } : rule;',
|
|
200
|
+
'}',
|
|
201
|
+
'function __poRuleSource(item, earlier, needsValues) {',
|
|
202
|
+
' var groupKey = __poSlug(__poText(item.groupKey));',
|
|
203
|
+
' var source = __poFindGroup(earlier, groupKey, __poSelectableTypes);',
|
|
204
|
+
' if (!source) { return null; }',
|
|
205
|
+
' var allowed = __poSourceValueKeys(source);',
|
|
206
|
+
' var listed = Array.isArray(item.valueKeys) ? item.valueKeys : (typeof item.valueKeys === "string" ? [item.valueKeys] : []);',
|
|
207
|
+
' var valueKeys = [];',
|
|
208
|
+
' for (var i = 0; i < listed.length; i++) {',
|
|
209
|
+
' var valueKey = __poSlug(__poText(listed[i]));',
|
|
210
|
+
' if (allowed.indexOf(valueKey) !== -1 && valueKeys.indexOf(valueKey) === -1) { valueKeys.push(valueKey); }',
|
|
211
|
+
' }',
|
|
212
|
+
' if (needsValues && valueKeys.length === 0) { return null; }',
|
|
213
|
+
' return { groupKey: groupKey, valueKeys: valueKeys };',
|
|
214
|
+
'}',
|
|
215
|
+
'function __poParseOverrides(raw, earlier, allowPerUnit) {',
|
|
216
|
+
' if (!Array.isArray(raw)) { return []; }',
|
|
217
|
+
' var out = [];',
|
|
218
|
+
' for (var i = 0; i < raw.length; i++) {',
|
|
219
|
+
' if (out.length >= __poLimits.priceOverrides) { break; }',
|
|
220
|
+
' var item = raw[i];',
|
|
221
|
+
' if (!__poIsObject(item)) { continue; }',
|
|
222
|
+
' var source = __poRuleSource(item, earlier, true);',
|
|
223
|
+
' if (!source) { continue; }',
|
|
224
|
+
' var price = __poParseRule(item.price);',
|
|
225
|
+
' out.push({ groupKey: source.groupKey, valueKeys: source.valueKeys, price: allowPerUnit ? price : __poUnitless(price) });',
|
|
226
|
+
' }',
|
|
227
|
+
' return out;',
|
|
228
|
+
'}',
|
|
229
|
+
'function __poParseVisibility(raw, earlier, limit) {',
|
|
230
|
+
' if (!Array.isArray(raw)) { return []; }',
|
|
231
|
+
' var out = [];',
|
|
232
|
+
' for (var i = 0; i < raw.length; i++) {',
|
|
233
|
+
' if (out.length >= limit) { break; }',
|
|
234
|
+
' var item = raw[i];',
|
|
235
|
+
' if (!__poIsObject(item) || __poOperators.indexOf(item.operator) === -1) { continue; }',
|
|
236
|
+
' var operator = item.operator;',
|
|
237
|
+
' var needsValues = operator === "is" || operator === "is-not";',
|
|
238
|
+
' var source = __poRuleSource(item, earlier, needsValues);',
|
|
239
|
+
' if (!source) { continue; }',
|
|
240
|
+
' out.push(needsValues ? { groupKey: source.groupKey, operator: operator, valueKeys: source.valueKeys } : { groupKey: source.groupKey, operator: operator });',
|
|
241
|
+
' }',
|
|
242
|
+
' return out;',
|
|
243
|
+
'}',
|
|
244
|
+
// Every stored string is trimmed, clipped, then trimmed again (a clip landing on a space leaves nothing a second parse would change).
|
|
245
|
+
'function __poParseValue(raw, taken, earlier) {',
|
|
246
|
+
' if (!__poIsObject(raw)) { return null; }',
|
|
247
|
+
' var label = __poClip(__poText(raw.label).trim(), __poLimits.labelChars, false).trim();',
|
|
248
|
+
' var value = { key: __poMintKey(__poSlug(__poText(raw.key)) || label, taken, "value"), label: label, price: __poUnitless(__poParseRule(raw.price)) };',
|
|
249
|
+
' var description = __poClip(__poText(raw.description).trim(), __poLimits.text, false).trim();',
|
|
250
|
+
' var color = __poClip(__poText(raw.color).trim(), 64, false).trim();',
|
|
251
|
+
' var imageUrl = __poClip(__poText(raw.imageUrl).trim(), 2048, false).trim();',
|
|
252
|
+
' if (description) { value.description = description; }',
|
|
253
|
+
' if (color) { value.color = color; }',
|
|
254
|
+
' if (imageUrl) { value.imageUrl = imageUrl; }',
|
|
255
|
+
' if (__poFlag(raw["default"])) { value["default"] = true; }',
|
|
256
|
+
' var overrides = __poParseOverrides(raw.priceWhen, earlier, false);',
|
|
257
|
+
' if (overrides.length > 0) { value.priceWhen = overrides; }',
|
|
258
|
+
' return value;',
|
|
259
|
+
'}',
|
|
260
|
+
'function __poParseValues(rawValues, earlier, type) {',
|
|
261
|
+
' var values = [];',
|
|
262
|
+
' var taken = [];',
|
|
263
|
+
' for (var i = 0; i < rawValues.length; i++) {',
|
|
264
|
+
' if (values.length >= __poLimits.values) { break; }',
|
|
265
|
+
' var value = __poParseValue(rawValues[i], taken, earlier);',
|
|
266
|
+
' if (value) { values.push(value); taken.push(value.key); }',
|
|
267
|
+
' }',
|
|
268
|
+
' if (type === "choice") {',
|
|
269
|
+
' var seen = false;',
|
|
270
|
+
' for (var j = 0; j < values.length; j++) {',
|
|
271
|
+
' if (values[j]["default"] && seen) { delete values[j]["default"]; }',
|
|
272
|
+
' else if (values[j]["default"]) { seen = true; }',
|
|
273
|
+
' }',
|
|
274
|
+
' }',
|
|
275
|
+
' return values;',
|
|
276
|
+
'}',
|
|
277
|
+
'function __poParseGroup(raw, earlier, taken) {',
|
|
278
|
+
' if (!__poIsObject(raw)) { return null; }',
|
|
279
|
+
' var label = __poClip(__poText(raw.label).trim(), __poLimits.labelChars, false).trim();',
|
|
280
|
+
' var rawValues = Array.isArray(raw.values) ? raw.values : [];',
|
|
281
|
+
' var type = __poReadType(raw) || (rawValues.length > 0 ? "choice" : "text");',
|
|
282
|
+
' var group = { key: __poMintKey(__poSlug(__poText(raw.key)) || label, taken, "option"), label: label, type: type, required: type === "toggle" ? false : __poFlag(raw.required) };',
|
|
283
|
+
' var helpText = __poClip(__poText(raw.helpText).trim(), __poLimits.text, false).trim();',
|
|
284
|
+
' if (helpText) { group.helpText = helpText; }',
|
|
285
|
+
' if (__poValueTypes.indexOf(type) !== -1) {',
|
|
286
|
+
' group.display = __poDisplays.indexOf(raw.display) !== -1 ? raw.display : "buttons";',
|
|
287
|
+
' group.values = __poParseValues(rawValues, earlier, type);',
|
|
288
|
+
' if (type === "multi-choice") {',
|
|
289
|
+
' var minSelected = __poWhole(raw.minSelected);',
|
|
290
|
+
' var maxSelected = __poWhole(raw.maxSelected);',
|
|
291
|
+
' if (minSelected !== undefined) { group.minSelected = minSelected; }',
|
|
292
|
+
' if (maxSelected !== undefined && maxSelected >= 1) { group.maxSelected = maxSelected; }',
|
|
293
|
+
' }',
|
|
294
|
+
' }',
|
|
295
|
+
' if (type === "text" || type === "long-text" || type === "number") {',
|
|
296
|
+
' var placeholder = __poClip(__poText(raw.placeholder).trim(), __poLimits.labelChars, false).trim();',
|
|
297
|
+
' if (placeholder) { group.placeholder = placeholder; }',
|
|
298
|
+
' }',
|
|
299
|
+
' if (type === "text" || type === "long-text") {',
|
|
300
|
+
' var maxLength = __poWhole(raw.maxLength);',
|
|
301
|
+
' if (maxLength !== undefined) { group.maxLength = Math.min(type === "text" ? __poLimits.text : __poLimits.longText, Math.max(1, maxLength)); }',
|
|
302
|
+
' }',
|
|
303
|
+
' if (type === "number") {',
|
|
304
|
+
' var min = __poFinite(raw.min);',
|
|
305
|
+
' var max = __poFinite(raw.max);',
|
|
306
|
+
' var step = __poFinite(raw.step);',
|
|
307
|
+
' var unit = __poClip(__poText(raw.unit).trim(), __poLimits.labelChars, false).trim();',
|
|
308
|
+
' var defaultValue = __poFinite(raw.defaultValue);',
|
|
309
|
+
' if (min !== undefined) { group.min = min; }',
|
|
310
|
+
' if (max !== undefined) { group.max = max; }',
|
|
311
|
+
' if (step !== undefined && step > 0) { group.step = step; }',
|
|
312
|
+
' if (unit) { group.unit = unit; }',
|
|
313
|
+
' if (defaultValue !== undefined) { group.defaultValue = defaultValue; }',
|
|
314
|
+
' }',
|
|
315
|
+
' if (__poPricedTypes.indexOf(type) !== -1) {',
|
|
316
|
+
' var price = __poParseRule(raw.price);',
|
|
317
|
+
' group.price = type === "number" ? price : __poUnitless(price);',
|
|
318
|
+
' var overrides = __poParseOverrides(raw.priceWhen, earlier, type === "number");',
|
|
319
|
+
' if (overrides.length > 0) { group.priceWhen = overrides; }',
|
|
320
|
+
' }',
|
|
321
|
+
' if (type === "upload") {',
|
|
322
|
+
' group.accept = __poAccepts.indexOf(raw.accept) !== -1 ? raw.accept : "any";',
|
|
323
|
+
' group.maxFiles = 1;',
|
|
324
|
+
' }',
|
|
325
|
+
' var visibleWhen = __poParseVisibility(raw.visibleWhen, earlier, __poLimits.rules);',
|
|
326
|
+
' if (visibleWhen.length > 0) { group.visibleWhen = visibleWhen; }',
|
|
327
|
+
' return group;',
|
|
328
|
+
'}',
|
|
329
|
+
'function __poParseGroups(raw) {',
|
|
330
|
+
' var source = raw;',
|
|
331
|
+
' if (typeof source === "string") {',
|
|
332
|
+
' var trimmed = source.trim();',
|
|
333
|
+
' if (trimmed === "") { return []; }',
|
|
334
|
+
' try { source = JSON.parse(trimmed); } catch (e) { return []; }',
|
|
335
|
+
' }',
|
|
336
|
+
' if (!Array.isArray(source)) { return []; }',
|
|
337
|
+
' var groups = [];',
|
|
338
|
+
' var taken = [];',
|
|
339
|
+
' for (var i = 0; i < source.length; i++) {',
|
|
340
|
+
' if (groups.length >= __poLimits.groups) { break; }',
|
|
341
|
+
' var group = __poParseGroup(source[i], groups, taken);',
|
|
342
|
+
' if (group) { groups.push(group); taken.push(group.key); }',
|
|
343
|
+
' }',
|
|
344
|
+
' return groups;',
|
|
345
|
+
'}',
|
|
346
|
+
// Serializing: one key order, so the same groups always give the same text; empty is null.
|
|
347
|
+
'function __poObjectLike(v) { return v !== null && typeof v === "object"; }',
|
|
348
|
+
'function __poCopy(target, source, fields) {',
|
|
349
|
+
' for (var i = 0; i < fields.length; i++) {',
|
|
350
|
+
' var v = source[fields[i]];',
|
|
351
|
+
' if (v !== undefined && v !== null) { target[fields[i]] = v; }',
|
|
352
|
+
' }',
|
|
353
|
+
' return target;',
|
|
354
|
+
'}',
|
|
355
|
+
'function __poOrderRule(rule) {',
|
|
356
|
+
' if (!rule || typeof rule !== "object") { return { mode: "none" }; }',
|
|
357
|
+
' if (rule.mode === "percent") { return { mode: "percent", percent: rule.percent }; }',
|
|
358
|
+
' if (rule.mode === "fixed" || rule.mode === "per-unit") { return { mode: rule.mode, amount: rule.amount }; }',
|
|
359
|
+
' return { mode: "none" };',
|
|
360
|
+
'}',
|
|
361
|
+
'function __poOrderOverride(override) {',
|
|
362
|
+
' return { groupKey: override.groupKey, valueKeys: Array.isArray(override.valueKeys) ? override.valueKeys.slice() : [], price: __poOrderRule(override.price) };',
|
|
363
|
+
'}',
|
|
364
|
+
'function __poOrderOverrides(list) {',
|
|
365
|
+
' var out = [];',
|
|
366
|
+
' for (var i = 0; i < list.length; i++) { if (__poObjectLike(list[i])) { out.push(__poOrderOverride(list[i])); } }',
|
|
367
|
+
' return out;',
|
|
368
|
+
'}',
|
|
369
|
+
'function __poOrderVisibility(rule) {',
|
|
370
|
+
' var out = { groupKey: rule.groupKey, operator: rule.operator };',
|
|
371
|
+
' if (Array.isArray(rule.valueKeys)) { out.valueKeys = rule.valueKeys.slice(); }',
|
|
372
|
+
' return out;',
|
|
373
|
+
'}',
|
|
374
|
+
'function __poOrderValue(value) {',
|
|
375
|
+
' var out = __poCopy({}, value, ["key", "label", "description", "color", "imageUrl"]);',
|
|
376
|
+
' out.price = __poOrderRule(value.price);',
|
|
377
|
+
' if (value["default"] === true) { out["default"] = true; }',
|
|
378
|
+
' if (Array.isArray(value.priceWhen)) { out.priceWhen = __poOrderOverrides(value.priceWhen); }',
|
|
379
|
+
' return out;',
|
|
380
|
+
'}',
|
|
381
|
+
'function __poOrderGroup(group) {',
|
|
382
|
+
' var out = __poCopy({}, group, ["key", "label", "type"]);',
|
|
383
|
+
' out.required = group.required === true;',
|
|
384
|
+
' __poCopy(out, group, ["helpText", "display"]);',
|
|
385
|
+
' if (Array.isArray(group.values)) {',
|
|
386
|
+
' var values = [];',
|
|
387
|
+
' for (var i = 0; i < group.values.length; i++) { if (__poObjectLike(group.values[i])) { values.push(__poOrderValue(group.values[i])); } }',
|
|
388
|
+
' out.values = values;',
|
|
389
|
+
' }',
|
|
390
|
+
' __poCopy(out, group, ["minSelected", "maxSelected", "placeholder", "maxLength", "min", "max", "step", "unit", "defaultValue"]);',
|
|
391
|
+
' if (group.price) { out.price = __poOrderRule(group.price); }',
|
|
392
|
+
' if (Array.isArray(group.priceWhen)) { out.priceWhen = __poOrderOverrides(group.priceWhen); }',
|
|
393
|
+
' __poCopy(out, group, ["accept", "maxFiles"]);',
|
|
394
|
+
' if (Array.isArray(group.visibleWhen)) {',
|
|
395
|
+
' var rules = [];',
|
|
396
|
+
' for (var r = 0; r < group.visibleWhen.length; r++) { if (__poObjectLike(group.visibleWhen[r])) { rules.push(__poOrderVisibility(group.visibleWhen[r])); } }',
|
|
397
|
+
' out.visibleWhen = rules;',
|
|
398
|
+
' }',
|
|
399
|
+
' return out;',
|
|
400
|
+
'}',
|
|
401
|
+
'function __poSerialize(groups) {',
|
|
402
|
+
' var present = [];',
|
|
403
|
+
' if (Array.isArray(groups)) {',
|
|
404
|
+
' for (var i = 0; i < groups.length; i++) { if (__poObjectLike(groups[i])) { present.push(__poOrderGroup(groups[i])); } }',
|
|
405
|
+
' }',
|
|
406
|
+
' return present.length === 0 ? null : JSON.stringify(present);',
|
|
407
|
+
'}',
|
|
408
|
+
// Uploaded files: https only (no javascript: or data: links), bounded fields, an id of letters, digits, _ . - (not only dots).
|
|
409
|
+
'function __poIsFileRef(ref) {',
|
|
410
|
+
' if (!ref || typeof ref !== "object" || Array.isArray(ref)) { return false; }',
|
|
411
|
+
' var url = ref.url;',
|
|
412
|
+
' if (typeof url !== "string" || url.length <= 8 || url.length > 2048) { return false; }',
|
|
413
|
+
' if (url.slice(0, 8).toLowerCase() !== "https://") { return false; }',
|
|
414
|
+
' if (typeof ref.id !== "string" || !/^[A-Za-z0-9_.-]{1,128}$/.test(ref.id) || !/[A-Za-z0-9_-]/.test(ref.id)) { return false; }',
|
|
415
|
+
' if (typeof ref.name !== "string" || ref.name.length > 255) { return false; }',
|
|
416
|
+
' if (typeof ref.mimeType !== "string" || ref.mimeType.length > 100) { return false; }',
|
|
417
|
+
' return typeof ref.size === "number" && isFinite(ref.size) && ref.size >= 0;',
|
|
418
|
+
'}',
|
|
419
|
+
'function __poFileRef(raw) {',
|
|
420
|
+
' var source = raw && typeof raw === "object" ? raw : {};',
|
|
421
|
+
' var size = -1;',
|
|
422
|
+
' if (typeof source.size === "number" && isFinite(source.size)) { size = source.size; }',
|
|
423
|
+
' else if (typeof source.size === "string" && source.size.trim() !== "") {',
|
|
424
|
+
' var parsed = Number(source.size.trim());',
|
|
425
|
+
' size = isFinite(parsed) ? parsed : -1;',
|
|
426
|
+
' }',
|
|
427
|
+
' return { id: typeof source.id === "string" ? source.id : "", name: typeof source.name === "string" ? source.name : "", size: size, url: typeof source.url === "string" ? source.url : "", mimeType: typeof source.mimeType === "string" ? source.mimeType : "" };',
|
|
428
|
+
'}',
|
|
429
|
+
// Whether a stored file renders as a thumbnail rather than a plain link (isImageFileRef).
|
|
430
|
+
'function __poIsImage(ref) { return __poIsObject(ref) && typeof ref.mimeType === "string" && ref.mimeType.toLowerCase().indexOf("image/") === 0; }',
|
|
431
|
+
// Configurations: [{key, value}] as a cart line carries them.
|
|
432
|
+
'function __poEntryValue(value) {',
|
|
433
|
+
' if (typeof value === "string" || typeof value === "boolean") { return value; }',
|
|
434
|
+
' if (typeof value === "number") { return isFinite(value) ? value : undefined; }',
|
|
435
|
+
' if (Array.isArray(value)) {',
|
|
436
|
+
' var out = [];',
|
|
437
|
+
' if (value.length > 0 && __poIsObject(value[0])) {',
|
|
438
|
+
' for (var i = 0; i < value.length; i++) { if (__poIsObject(value[i])) { out.push(__poFileRef(value[i])); } }',
|
|
439
|
+
' return out;',
|
|
440
|
+
' }',
|
|
441
|
+
' for (var j = 0; j < value.length; j++) {',
|
|
442
|
+
' if (typeof value[j] === "string" || (typeof value[j] === "number" && isFinite(value[j]))) { out.push(__poText(value[j])); }',
|
|
443
|
+
' }',
|
|
444
|
+
' return out;',
|
|
445
|
+
' }',
|
|
446
|
+
' if (__poIsObject(value)) { return [__poFileRef(value)]; }',
|
|
447
|
+
' return undefined;',
|
|
448
|
+
'}',
|
|
449
|
+
'function __poParseEntries(raw) {',
|
|
450
|
+
' var source = raw;',
|
|
451
|
+
' if (typeof source === "string") {',
|
|
452
|
+
' var trimmed = source.trim();',
|
|
453
|
+
' if (trimmed === "") { return []; }',
|
|
454
|
+
' try { source = JSON.parse(trimmed); } catch (e) { return []; }',
|
|
455
|
+
' }',
|
|
456
|
+
' if (!Array.isArray(source)) { return []; }',
|
|
457
|
+
' var entries = [];',
|
|
458
|
+
' var seen = [];',
|
|
459
|
+
' for (var i = 0; i < source.length; i++) {',
|
|
460
|
+
' var item = source[i];',
|
|
461
|
+
' if (!__poIsObject(item)) { continue; }',
|
|
462
|
+
' var key = __poText(item.key).trim();',
|
|
463
|
+
' if (key === "" || seen.indexOf(key) !== -1) { continue; }',
|
|
464
|
+
' var value = __poEntryValue(item.value);',
|
|
465
|
+
' if (value === undefined) { continue; }',
|
|
466
|
+
' entries.push({ key: key, value: value });',
|
|
467
|
+
' seen.push(key);',
|
|
468
|
+
' }',
|
|
469
|
+
' return entries;',
|
|
470
|
+
'}',
|
|
471
|
+
'function __poCanonicalValue(value) {',
|
|
472
|
+
' if (typeof value === "string") {',
|
|
473
|
+
' var trimmed = value.trim();',
|
|
474
|
+
' return trimmed === "" ? undefined : trimmed;',
|
|
475
|
+
' }',
|
|
476
|
+
' if (typeof value === "boolean") { return value ? true : undefined; }',
|
|
477
|
+
' if (typeof value === "number") { return value; }',
|
|
478
|
+
' if (value.length === 0) { return undefined; }',
|
|
479
|
+
' var out = [];',
|
|
480
|
+
' var i;',
|
|
481
|
+
' if (typeof value[0] === "object") {',
|
|
482
|
+
' for (i = 0; i < value.length; i++) { out.push({ id: value[i].id, name: value[i].name, size: value[i].size, url: value[i].url, mimeType: value[i].mimeType }); }',
|
|
483
|
+
' return out;',
|
|
484
|
+
' }',
|
|
485
|
+
' for (i = 0; i < value.length; i++) {',
|
|
486
|
+
' var key = value[i].trim();',
|
|
487
|
+
' if (key !== "" && out.indexOf(key) === -1) { out.push(key); }',
|
|
488
|
+
' }',
|
|
489
|
+
' return out.length > 0 ? out.sort() : undefined;',
|
|
490
|
+
'}',
|
|
491
|
+
'function __poSortByKey(list) {',
|
|
492
|
+
' for (var i = 1; i < list.length; i++) {',
|
|
493
|
+
' var item = list[i];',
|
|
494
|
+
' var j = i - 1;',
|
|
495
|
+
' while (j >= 0 && list[j].key > item.key) { list[j + 1] = list[j]; j--; }',
|
|
496
|
+
' list[j + 1] = item;',
|
|
497
|
+
' }',
|
|
498
|
+
' return list;',
|
|
499
|
+
'}',
|
|
500
|
+
'function __poCanonicalEntries(raw) {',
|
|
501
|
+
' var parsed = __poParseEntries(raw);',
|
|
502
|
+
' var out = [];',
|
|
503
|
+
' for (var i = 0; i < parsed.length; i++) {',
|
|
504
|
+
' var value = __poCanonicalValue(parsed[i].value);',
|
|
505
|
+
' if (value !== undefined) { out.push({ key: parsed[i].key, value: value }); }',
|
|
506
|
+
' }',
|
|
507
|
+
' return __poSortByKey(out);',
|
|
508
|
+
'}',
|
|
509
|
+
'function __poCanonical(entries) {',
|
|
510
|
+
' var list = __poCanonicalEntries(entries);',
|
|
511
|
+
' return list.length === 0 ? "" : JSON.stringify(list);',
|
|
512
|
+
'}',
|
|
513
|
+
// The line key hashes this form: an upload reduced to its file ids, so renaming the file keeps the line.
|
|
514
|
+
'function __poCanonicalForKey(entries) {',
|
|
515
|
+
' var list = __poCanonicalEntries(entries);',
|
|
516
|
+
' if (list.length === 0) { return ""; }',
|
|
517
|
+
' var out = [];',
|
|
518
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
519
|
+
' var value = list[i].value;',
|
|
520
|
+
' if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object") {',
|
|
521
|
+
' var ids = [];',
|
|
522
|
+
' for (var j = 0; j < value.length; j++) { ids.push(value[j].id); }',
|
|
523
|
+
' value = ids;',
|
|
524
|
+
' }',
|
|
525
|
+
' out.push({ key: list[i].key, value: value });',
|
|
526
|
+
' }',
|
|
527
|
+
' return JSON.stringify(out);',
|
|
528
|
+
'}',
|
|
529
|
+
'function __poHex8(n) { return ("0000000" + n.toString(16)).slice(-8); }',
|
|
530
|
+
// djb2 and FNV-1a over the UTF-16 code units: 16 lowercase hex characters.
|
|
531
|
+
'function __poHash(text) {',
|
|
532
|
+
' var djb = 5381;',
|
|
533
|
+
' var fnv = 2166136261;',
|
|
534
|
+
' for (var i = 0; i < text.length; i++) {',
|
|
535
|
+
' var code = text.charCodeAt(i);',
|
|
536
|
+
' djb = ((djb << 5) + djb + code) >>> 0;',
|
|
537
|
+
' fnv = (fnv ^ code) >>> 0;',
|
|
538
|
+
' fnv = ((fnv << 24) + fnv * 403) >>> 0;',
|
|
539
|
+
' }',
|
|
540
|
+
' return __poHex8(djb) + __poHex8(fnv);',
|
|
541
|
+
'}',
|
|
542
|
+
'function __poKey(entries) {',
|
|
543
|
+
' var text = __poCanonicalForKey(entries);',
|
|
544
|
+
' return text === "" ? "" : __poHash(text);',
|
|
545
|
+
'}',
|
|
546
|
+
// Defaults: a pick-one default, the pick-several defaults, a number starting value.
|
|
547
|
+
'function __poDefaultSelection(groups) {',
|
|
548
|
+
' var selection = {};',
|
|
549
|
+
' var list = Array.isArray(groups) ? groups : [];',
|
|
550
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
551
|
+
' var group = list[i];',
|
|
552
|
+
' if (!__poIsObject(group)) { continue; }',
|
|
553
|
+
' var values = Array.isArray(group.values) ? group.values : [];',
|
|
554
|
+
' var j;',
|
|
555
|
+
' if (group.type === "choice") {',
|
|
556
|
+
' for (j = 0; j < values.length; j++) { if (__poIsObject(values[j]) && values[j]["default"] === true) { selection[group.key] = values[j].key; break; } }',
|
|
557
|
+
' } else if (group.type === "multi-choice") {',
|
|
558
|
+
' var keys = [];',
|
|
559
|
+
' for (j = 0; j < values.length; j++) { if (__poIsObject(values[j]) && values[j]["default"] === true) { keys.push(values[j].key); } }',
|
|
560
|
+
' if (keys.length > 0) { selection[group.key] = keys; }',
|
|
561
|
+
' } else if (group.type === "number" && typeof group.defaultValue === "number" && isFinite(group.defaultValue)) {',
|
|
562
|
+
' selection[group.key] = group.defaultValue;',
|
|
563
|
+
' }',
|
|
564
|
+
' }',
|
|
565
|
+
' return selection;',
|
|
566
|
+
'}',
|
|
567
|
+
'function __poEntriesFromSelection(selection) {',
|
|
568
|
+
' if (!__poIsObject(selection)) { return []; }',
|
|
569
|
+
' var entries = [];',
|
|
570
|
+
' var keys = Object.keys(selection);',
|
|
571
|
+
' for (var i = 0; i < keys.length; i++) {',
|
|
572
|
+
' var value = selection[keys[i]];',
|
|
573
|
+
' if (value !== undefined && value !== null) { entries.push({ key: keys[i], value: value }); }',
|
|
574
|
+
' }',
|
|
575
|
+
' return entries;',
|
|
576
|
+
'}',
|
|
577
|
+
'function __poDefaultEntries(groups) { return __poEntriesFromSelection(__poDefaultSelection(groups)); }',
|
|
578
|
+
// Pricing: a price override applies while its EARLIER source group is shown and set to one of its values.
|
|
579
|
+
// Answers are read from own properties only, so a group keyed constructor is unanswered until answered.
|
|
580
|
+
'function __poSelectionIncludes(selection, groupKey, valueKeys) {',
|
|
581
|
+
' var current = Object.prototype.hasOwnProperty.call(selection, groupKey) ? selection[groupKey] : undefined;',
|
|
582
|
+
' var wanted = Array.isArray(valueKeys) ? valueKeys : [];',
|
|
583
|
+
' if (current === true) { return wanted.indexOf("on") !== -1; }',
|
|
584
|
+
' if (typeof current === "string") { return wanted.indexOf(current) !== -1; }',
|
|
585
|
+
' if (Array.isArray(current)) {',
|
|
586
|
+
' for (var i = 0; i < current.length; i++) { if (typeof current[i] === "string" && wanted.indexOf(current[i]) !== -1) { return true; } }',
|
|
587
|
+
' }',
|
|
588
|
+
' return false;',
|
|
589
|
+
'}',
|
|
590
|
+
// The price variant in force: the index of the first matching override, else "d" (the default price). The last segment of a pv: key.
|
|
591
|
+
'function __poEffectiveVariant(target, selection, visibleKeys) {',
|
|
592
|
+
' var overrides = target && Array.isArray(target.priceWhen) ? target.priceWhen : [];',
|
|
593
|
+
' var visible = Array.isArray(visibleKeys) ? visibleKeys : [];',
|
|
594
|
+
' for (var i = 0; i < overrides.length; i++) {',
|
|
595
|
+
' var override = overrides[i];',
|
|
596
|
+
' if (override && visible.indexOf(override.groupKey) !== -1 && __poSelectionIncludes(selection || {}, override.groupKey, override.valueKeys)) { return i; }',
|
|
597
|
+
' }',
|
|
598
|
+
' return "d";',
|
|
599
|
+
'}',
|
|
600
|
+
'function __poEffectiveRule(target, selection, visibleKeys) {',
|
|
601
|
+
' var variant = __poEffectiveVariant(target, selection, visibleKeys);',
|
|
602
|
+
' var rule = variant === "d" ? (target ? target.price : undefined) : target.priceWhen[variant].price;',
|
|
603
|
+
' return rule && typeof rule === "object" ? rule : { mode: "none" };',
|
|
604
|
+
'}',
|
|
605
|
+
// pv:pid|gk|vk|<i or d> for a value; valueKey null / undefined gives pv:pid|gk|<i or d> for a priced group (priceVariantActiveKey).
|
|
606
|
+
'function __poPriceVariantKey(productId, groupKey, valueKey, variant) {',
|
|
607
|
+
' var scope = valueKey === null || valueKey === undefined ? productId + "|" + groupKey : productId + "|" + groupKey + "|" + valueKey;',
|
|
608
|
+
' return "pv:" + scope + "|" + variant;',
|
|
609
|
+
'}',
|
|
610
|
+
// A negative quantity priced per unit gives NaN, which the resolver refuses as out-of-range.
|
|
611
|
+
'function __poRuleDelta(rule, base, quantity) {',
|
|
612
|
+
' var delta = 0;',
|
|
613
|
+
' if (rule.mode === "fixed") { delta = __poRound2(Math.max(0, __poSafe(rule.amount))); }',
|
|
614
|
+
' else if (rule.mode === "percent") {',
|
|
615
|
+
' var percent = Math.min(1000, Math.max(0, __poSafe(rule.percent)));',
|
|
616
|
+
' delta = __poRound2(base * percent / 100);',
|
|
617
|
+
' } else if (rule.mode === "per-unit") { delta = quantity < 0 ? NaN : __poRound2(Math.max(0, __poSafe(rule.amount)) * quantity); }',
|
|
618
|
+
' return Math.max(0, delta);',
|
|
619
|
+
'}',
|
|
620
|
+
// Whether a number falls between two steps counted from min (else 0), with a relative tolerance (isNumberOffStep).
|
|
621
|
+
'function __poOffStep(step, min, number) {',
|
|
622
|
+
' if (typeof step !== "number" || !(step > 0) || !isFinite(step)) { return false; }',
|
|
623
|
+
' var origin = typeof min === "number" && isFinite(min) ? min : 0;',
|
|
624
|
+
' var steps = (number - origin) / step;',
|
|
625
|
+
' return Math.abs(steps - Math.round(steps)) > 1e-9 * Math.max(1, Math.abs(steps));',
|
|
626
|
+
'}',
|
|
627
|
+
'function __poIsVisible(group, selection, visibleKeys) {',
|
|
628
|
+
' var rules = Array.isArray(group.visibleWhen) ? group.visibleWhen : [];',
|
|
629
|
+
' for (var i = 0; i < rules.length; i++) {',
|
|
630
|
+
' var rule = rules[i];',
|
|
631
|
+
' if (!__poIsObject(rule)) { continue; }',
|
|
632
|
+
' var current = Object.prototype.hasOwnProperty.call(selection, rule.groupKey) ? selection[rule.groupKey] : undefined;',
|
|
633
|
+
' var answered = visibleKeys.indexOf(rule.groupKey) !== -1 && current !== undefined && current !== null;',
|
|
634
|
+
' var holds = true;',
|
|
635
|
+
' if (rule.operator === "is") { holds = answered && __poSelectionIncludes(selection, rule.groupKey, rule.valueKeys); }',
|
|
636
|
+
' else if (rule.operator === "is-not") { holds = !(answered && __poSelectionIncludes(selection, rule.groupKey, rule.valueKeys)); }',
|
|
637
|
+
' else if (rule.operator === "is-set") { holds = answered; }',
|
|
638
|
+
' else if (rule.operator === "is-not-set") { holds = !answered; }',
|
|
639
|
+
' if (!holds) { return false; }',
|
|
640
|
+
' }',
|
|
641
|
+
' return true;',
|
|
642
|
+
'}',
|
|
643
|
+
'function __poValueKeysOf(values) {',
|
|
644
|
+
' var keys = [];',
|
|
645
|
+
' for (var i = 0; i < values.length; i++) { if (__poIsObject(values[i])) { keys.push(values[i].key); } }',
|
|
646
|
+
' return keys;',
|
|
647
|
+
'}',
|
|
648
|
+
// One group's answer, checked; null means unanswered. Problems are pushed as code:groupKey.
|
|
649
|
+
'function __poReadAnswer(group, raw, errors) {',
|
|
650
|
+
' if (raw === undefined) { return null; }',
|
|
651
|
+
' var values = Array.isArray(group.values) ? group.values : [];',
|
|
652
|
+
' var tag = ":" + group.key;',
|
|
653
|
+
' var i;',
|
|
654
|
+
' if (group.type === "choice" || group.type === "multi-choice") {',
|
|
655
|
+
' var known = __poValueKeysOf(values);',
|
|
656
|
+
' var listed = Array.isArray(raw) ? raw : [raw];',
|
|
657
|
+
' var picked = [];',
|
|
658
|
+
' for (i = 0; i < listed.length; i++) {',
|
|
659
|
+
' var key = __poText(listed[i]).trim();',
|
|
660
|
+
' if (key === "") { continue; }',
|
|
661
|
+
' if (known.indexOf(key) === -1) { if (errors.indexOf("unknown-value" + tag) === -1) { errors.push("unknown-value" + tag); } }',
|
|
662
|
+
' else if (picked.indexOf(key) === -1) { picked.push(key); }',
|
|
663
|
+
' }',
|
|
664
|
+
' if (picked.length === 0) { return null; }',
|
|
665
|
+
' var ordered = [];',
|
|
666
|
+
' var valueKeys = [];',
|
|
667
|
+
' var labels = [];',
|
|
668
|
+
' for (i = 0; i < values.length; i++) {',
|
|
669
|
+
' if (__poIsObject(values[i]) && picked.indexOf(values[i].key) !== -1) { ordered.push(values[i]); valueKeys.push(values[i].key); labels.push(__poText(values[i].label) || values[i].key); }',
|
|
670
|
+
' }',
|
|
671
|
+
' if (group.type === "choice") {',
|
|
672
|
+
' if (valueKeys.length > 1) { errors.push("too-many" + tag); }',
|
|
673
|
+
' return { selection: valueKeys[0], canonical: valueKeys[0], value: valueKeys[0], valueLabel: __poText(ordered[0].label) || valueKeys[0], valueKeys: [valueKeys[0]] };',
|
|
674
|
+
' }',
|
|
675
|
+
' var minSelected = Math.max(group.required ? 1 : 0, __poSafe(group.minSelected));',
|
|
676
|
+
' if (valueKeys.length < minSelected) { errors.push("too-few" + tag); }',
|
|
677
|
+
' if (typeof group.maxSelected === "number" && valueKeys.length > group.maxSelected) { errors.push("too-many" + tag); }',
|
|
678
|
+
' return { selection: valueKeys, canonical: valueKeys, value: valueKeys, valueLabel: labels.join(", "), valueKeys: valueKeys };',
|
|
679
|
+
' }',
|
|
680
|
+
' if (group.type === "text" || group.type === "long-text") {',
|
|
681
|
+
' var text = typeof raw === "string" ? raw.trim() : (typeof raw === "number" ? String(raw) : "");',
|
|
682
|
+
' if (text === "") { return null; }',
|
|
683
|
+
' var limit = group.type === "text" ? __poLimits.text : __poLimits.longText;',
|
|
684
|
+
' var maxLength = typeof group.maxLength === "number" ? Math.min(limit, group.maxLength) : limit;',
|
|
685
|
+
' if (text.length > maxLength) { errors.push("text-too-long" + tag); }',
|
|
686
|
+
' return { selection: text, canonical: text, value: text, valueLabel: text };',
|
|
687
|
+
' }',
|
|
688
|
+
' if (group.type === "number") {',
|
|
689
|
+
' if (typeof raw === "string" && raw.trim() === "") { return null; }',
|
|
690
|
+
' var number = __poFinite(raw);',
|
|
691
|
+
' if (number === undefined) { errors.push("not-a-number" + tag); return null; }',
|
|
692
|
+
' if ((typeof group.min === "number" && number < group.min) || (typeof group.max === "number" && number > group.max)) { errors.push("out-of-range" + tag); }',
|
|
693
|
+
' else if (__poOffStep(group.step, group.min, number)) { errors.push("off-step" + tag); }',
|
|
694
|
+
' var unit = __poText(group.unit);',
|
|
695
|
+
' return { selection: number, canonical: number, value: number, valueLabel: unit ? number + " " + unit : String(number), number: number };',
|
|
696
|
+
' }',
|
|
697
|
+
' if (group.type === "toggle") {',
|
|
698
|
+
' if (!__poFlag(raw)) { return null; }',
|
|
699
|
+
' return { selection: true, canonical: true, value: true, valueLabel: "Yes" };',
|
|
700
|
+
' }',
|
|
701
|
+
// An upload is a safe ref of a type the group accepts (unknown accept reads as any; never SVG), at most uploadBytes.
|
|
702
|
+
' if (group.type === "upload") {',
|
|
703
|
+
' var items = Array.isArray(raw) ? raw : [raw];',
|
|
704
|
+
' var files = [];',
|
|
705
|
+
' var allowed = __poUploadMime[__poAccepts.indexOf(group.accept) !== -1 ? group.accept : "any"];',
|
|
706
|
+
' for (i = 0; i < items.length; i++) {',
|
|
707
|
+
' if (__poIsFileRef(items[i]) && allowed.indexOf(items[i].mimeType.trim().toLowerCase()) !== -1 && items[i].size <= __poLimits.uploadBytes) { files.push(items[i]); }',
|
|
708
|
+
' else if (!(typeof items[i] === "string" && items[i].trim() === "")) { if (errors.indexOf("bad-file" + tag) === -1) { errors.push("bad-file" + tag); } }',
|
|
709
|
+
' }',
|
|
710
|
+
' if (files.length === 0) { return null; }',
|
|
711
|
+
' if (files.length > 1) { errors.push("too-many-files" + tag); }',
|
|
712
|
+
' var ids = [];',
|
|
713
|
+
' var names = [];',
|
|
714
|
+
' var refs = [];',
|
|
715
|
+
' for (i = 0; i < files.length; i++) {',
|
|
716
|
+
' ids.push(files[i].id);',
|
|
717
|
+
' names.push(files[i].name || files[i].id);',
|
|
718
|
+
' refs.push({ id: files[i].id, name: files[i].name, size: files[i].size, url: files[i].url, mimeType: files[i].mimeType });',
|
|
719
|
+
' }',
|
|
720
|
+
' return { selection: ids, canonical: refs, value: ids, valueLabel: names.join(", "), files: files };',
|
|
721
|
+
' }',
|
|
722
|
+
' return null;',
|
|
723
|
+
'}',
|
|
724
|
+
'function __poPriceAnswer(group, read, base, selection, visibleKeys) {',
|
|
725
|
+
' if (group.type === "choice" || group.type === "multi-choice") {',
|
|
726
|
+
' var sum = 0;',
|
|
727
|
+
' var values = Array.isArray(group.values) ? group.values : [];',
|
|
728
|
+
' var keys = read.valueKeys || [];',
|
|
729
|
+
' for (var i = 0; i < keys.length; i++) {',
|
|
730
|
+
' for (var j = 0; j < values.length; j++) {',
|
|
731
|
+
' if (__poIsObject(values[j]) && values[j].key === keys[i]) { sum += __poRuleDelta(__poEffectiveRule(values[j], selection, visibleKeys), base, 1); break; }',
|
|
732
|
+
' }',
|
|
733
|
+
' }',
|
|
734
|
+
' return __poRound2(sum);',
|
|
735
|
+
' }',
|
|
736
|
+
' var quantity = group.type === "number" ? __poSafe(read.number) : 1;',
|
|
737
|
+
' return __poRuleDelta(__poEffectiveRule(group, selection, visibleKeys), base, quantity);',
|
|
738
|
+
'}',
|
|
739
|
+
// Labels: the short one-line label (values clipped to 80, whole <= 500) and the full details lines.
|
|
740
|
+
'function __poLabel(entries) {',
|
|
741
|
+
' var list = Array.isArray(entries) ? entries : [];',
|
|
742
|
+
' var parts = [];',
|
|
743
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
744
|
+
' if (!__poIsObject(list[i])) { continue; }',
|
|
745
|
+
' var name = __poOneLine(__poText(list[i].label));',
|
|
746
|
+
' var value = __poClip(__poOneLine(__poText(list[i].valueLabel)), 80, true);',
|
|
747
|
+
' parts.push(name ? name + ": " + value : value);',
|
|
748
|
+
' }',
|
|
749
|
+
' return __poClip(parts.join(" · "), __poLimits.configurationLabelChars, true);',
|
|
750
|
+
'}',
|
|
751
|
+
'function __poDetails(entries) {',
|
|
752
|
+
' var list = Array.isArray(entries) ? entries : [];',
|
|
753
|
+
' var lines = [];',
|
|
754
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
755
|
+
' if (!__poIsObject(list[i])) { continue; }',
|
|
756
|
+
' var name = __poText(list[i].label);',
|
|
757
|
+
' var value = __poText(list[i].valueLabel);',
|
|
758
|
+
' lines.push(name ? name + ": " + value : value);',
|
|
759
|
+
' }',
|
|
760
|
+
' return lines.join(String.fromCharCode(10));',
|
|
761
|
+
'}',
|
|
762
|
+
// Also takes formatPriceRuleLabel's shape: __poPriceLabel(rule, {symbol, position, taxRate, unit}).
|
|
763
|
+
'function __poPriceLabel(rule, symbol, position, taxRate, unit) {',
|
|
764
|
+
' if (__poIsObject(symbol)) { position = symbol.position; taxRate = symbol.taxRate; unit = symbol.unit; symbol = symbol.symbol; }',
|
|
765
|
+
' if (!rule || typeof rule !== "object") { return ""; }',
|
|
766
|
+
' if (rule.mode === "percent") {',
|
|
767
|
+
' var percent = Math.min(1000, Math.max(0, __poSafe(rule.percent)));',
|
|
768
|
+
' return percent > 0 ? "+" + __poRound2(percent) + "%" : "";',
|
|
769
|
+
' }',
|
|
770
|
+
' if (rule.mode !== "fixed" && rule.mode !== "per-unit") { return ""; }',
|
|
771
|
+
' var amount = Math.max(0, __poSafe(rule.amount));',
|
|
772
|
+
' if (amount <= 0) { return ""; }',
|
|
773
|
+
' var rate = __poSafe(taxRate);',
|
|
774
|
+
' var gross = rate > 0 ? __poRound2(amount * (1 + rate / 100)) : __poRound2(amount);',
|
|
775
|
+
' var fixed = gross.toFixed(2);',
|
|
776
|
+
' var money = position === "after" ? fixed + " " + (symbol || "") : (symbol || "") + fixed;',
|
|
777
|
+
' if (rule.mode === "fixed") { return "+" + money; }',
|
|
778
|
+
' return unit ? "+" + money + " / " + unit : "+" + money + " each";',
|
|
779
|
+
'}',
|
|
780
|
+
// Resolving: ONE forward pass. Hidden groups are dropped, each entry priced by its effective rule, the sum rounded once more.
|
|
781
|
+
// An entry over maxAmount (or NaN / Infinity) is out-of-range and charges 0. pricesDisabled is true or {pricesDisabled: true}.
|
|
782
|
+
'function __poResolve(base, groups, configuration, pricesDisabled) {',
|
|
783
|
+
' var disabled = pricesDisabled === true || (__poIsObject(pricesDisabled) && pricesDisabled.pricesDisabled === true);',
|
|
784
|
+
' var charged = __poSafe(base);',
|
|
785
|
+
' var list = [];',
|
|
786
|
+
' var i;',
|
|
787
|
+
' var j;',
|
|
788
|
+
' if (Array.isArray(groups)) { for (i = 0; i < groups.length; i++) { if (__poIsObject(groups[i])) { list.push(groups[i]); } } }',
|
|
789
|
+
' var answers = __poParseEntries(configuration);',
|
|
790
|
+
' var errors = [];',
|
|
791
|
+
' var missingKeys = [];',
|
|
792
|
+
' var missingLabels = [];',
|
|
793
|
+
' var visibleKeys = [];',
|
|
794
|
+
' var selection = {};',
|
|
795
|
+
' var entries = [];',
|
|
796
|
+
' var canonicalEntries = [];',
|
|
797
|
+
' var total = 0;',
|
|
798
|
+
' for (i = 0; i < answers.length; i++) {',
|
|
799
|
+
' var known = false;',
|
|
800
|
+
' for (j = 0; j < list.length; j++) { if (list[j].key === answers[i].key) { known = true; break; } }',
|
|
801
|
+
' if (!known) { errors.push("unknown-option:" + answers[i].key); }',
|
|
802
|
+
' }',
|
|
803
|
+
' for (i = 0; i < list.length; i++) {',
|
|
804
|
+
' var group = list[i];',
|
|
805
|
+
' if (!__poIsVisible(group, selection, visibleKeys)) { continue; }',
|
|
806
|
+
' visibleKeys.push(group.key);',
|
|
807
|
+
' var raw = undefined;',
|
|
808
|
+
' for (j = 0; j < answers.length; j++) { if (answers[j].key === group.key) { raw = answers[j].value; break; } }',
|
|
809
|
+
' var read = __poReadAnswer(group, raw, errors);',
|
|
810
|
+
' if (read === null) {',
|
|
811
|
+
' if (group.required) { missingKeys.push(group.key); missingLabels.push(__poText(group.label) || "Option " + (i + 1)); }',
|
|
812
|
+
' continue;',
|
|
813
|
+
' }',
|
|
814
|
+
' var priceDelta = disabled ? 0 : __poPriceAnswer(group, read, charged, selection, visibleKeys);',
|
|
815
|
+
' if (!(priceDelta <= __poLimits.maxAmount)) {',
|
|
816
|
+
' if (errors.indexOf("out-of-range:" + group.key) === -1) { errors.push("out-of-range:" + group.key); }',
|
|
817
|
+
' priceDelta = 0;',
|
|
818
|
+
' }',
|
|
819
|
+
' total += priceDelta;',
|
|
820
|
+
' selection[group.key] = read.selection;',
|
|
821
|
+
' canonicalEntries.push({ key: group.key, value: read.canonical });',
|
|
822
|
+
' var entry = { key: group.key, label: __poText(group.label), type: group.type, value: read.value, valueLabel: read.valueLabel, priceDelta: priceDelta };',
|
|
823
|
+
' if (read.files) { entry.files = read.files; }',
|
|
824
|
+
' entries.push(entry);',
|
|
825
|
+
' }',
|
|
826
|
+
' var canonical = __poCanonical(canonicalEntries);',
|
|
827
|
+
' if (canonical.length > __poLimits.configurationChars) { errors.push("too-long"); }',
|
|
828
|
+
' return { delta: disabled ? 0 : __poRound2(total), entries: entries, canonical: canonical, key: __poKey(canonicalEntries), label: __poLabel(entries), details: __poDetails(entries), valid: errors.length === 0 && missingKeys.length === 0, errors: errors, missingKeys: missingKeys, missingLabels: missingLabels, visibleKeys: visibleKeys };',
|
|
829
|
+
'}',
|
|
830
|
+
// A product row: gift cards and recurring products never charge for options.
|
|
831
|
+
'function __poResolveForRow(row, base, configuration) {',
|
|
832
|
+
' var source = __poIsObject(row) ? row : {};',
|
|
833
|
+
' var disabled = __poFlag(source.is_gift_card) || __poText(source.payment_type).trim().toLowerCase() === "recurring";',
|
|
834
|
+
' return __poResolve(base, __poParseGroups(source.option_groups), configuration, disabled);',
|
|
835
|
+
'}',
|
|
836
|
+
'function __poRequiresInput(groups) {',
|
|
837
|
+
' return !__poResolve(0, groups, __poDefaultEntries(groups), false).valid;',
|
|
838
|
+
'}',
|
|
839
|
+
'function __poQuickAdd(groups, base, pricesDisabled) {',
|
|
840
|
+
' var resolved = __poResolve(base, groups, __poDefaultEntries(groups), pricesDisabled);',
|
|
841
|
+
' return resolved.valid && resolved.delta === 0;',
|
|
842
|
+
'}',
|
|
843
|
+
// Localizing: structure and prices from input.main, label / help / placeholder / value strings from input.clone by key.
|
|
844
|
+
// Also takes localizeProductOptionGroups' shape: __poLocalize(main, clone), main being a list or its JSON.
|
|
845
|
+
'function __poCopyObject(source) {',
|
|
846
|
+
' var out = {};',
|
|
847
|
+
' for (var k in source) { if (Object.prototype.hasOwnProperty.call(source, k)) { out[k] = source[k]; } }',
|
|
848
|
+
' return out;',
|
|
849
|
+
'}',
|
|
850
|
+
'function __poLocalize(input) {',
|
|
851
|
+
' var source = __poIsObject(input) ? input : { main: input, clone: arguments[1] };',
|
|
852
|
+
' var groups = __poParseGroups(source.main);',
|
|
853
|
+
' var clones = __poParseGroups(source.clone);',
|
|
854
|
+
' if (clones.length === 0) { return groups; }',
|
|
855
|
+
' var out = [];',
|
|
856
|
+
' for (var i = 0; i < groups.length; i++) {',
|
|
857
|
+
' var group = groups[i];',
|
|
858
|
+
' var translated = __poFindGroup(clones, group.key, null);',
|
|
859
|
+
' if (!translated) { out.push(group); continue; }',
|
|
860
|
+
' var next = __poCopyObject(group);',
|
|
861
|
+
' next.label = translated.label || group.label;',
|
|
862
|
+
' if (group.helpText && translated.helpText) { next.helpText = translated.helpText; }',
|
|
863
|
+
' if (group.placeholder && translated.placeholder) { next.placeholder = translated.placeholder; }',
|
|
864
|
+
' if (Array.isArray(group.values)) {',
|
|
865
|
+
' var translatedValues = Array.isArray(translated.values) ? translated.values : [];',
|
|
866
|
+
' var values = [];',
|
|
867
|
+
' for (var j = 0; j < group.values.length; j++) {',
|
|
868
|
+
' var value = group.values[j];',
|
|
869
|
+
' var match = null;',
|
|
870
|
+
' for (var k = 0; k < translatedValues.length; k++) { if (translatedValues[k].key === value.key) { match = translatedValues[k]; break; } }',
|
|
871
|
+
' if (!match) { values.push(value); continue; }',
|
|
872
|
+
' var localized = __poCopyObject(value);',
|
|
873
|
+
' localized.label = match.label || value.label;',
|
|
874
|
+
' if (value.description && match.description) { localized.description = match.description; }',
|
|
875
|
+
' values.push(localized);',
|
|
876
|
+
' }',
|
|
877
|
+
' next.values = values;',
|
|
878
|
+
' }',
|
|
879
|
+
' out.push(next);',
|
|
880
|
+
' }',
|
|
881
|
+
' return out;',
|
|
882
|
+
'}',
|
|
883
|
+
// Order-line snapshots: v1 {v, basePrice, priceDelta, entries} or the legacy compact [{key, value}].
|
|
884
|
+
'function __poNullable(v) {',
|
|
885
|
+
' var parsed = __poFinite(v);',
|
|
886
|
+
' return parsed === undefined ? null : parsed;',
|
|
887
|
+
'}',
|
|
888
|
+
'function __poSafeFiles(raw) {',
|
|
889
|
+
' var list = Array.isArray(raw) ? raw : [];',
|
|
890
|
+
' var out = [];',
|
|
891
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
892
|
+
' if (__poIsFileRef(list[i])) { out.push({ id: list[i].id, name: list[i].name, size: list[i].size, url: list[i].url, mimeType: list[i].mimeType }); }',
|
|
893
|
+
' }',
|
|
894
|
+
' return out;',
|
|
895
|
+
'}',
|
|
896
|
+
'function __poFileNames(files) {',
|
|
897
|
+
' var names = [];',
|
|
898
|
+
' for (var i = 0; i < files.length; i++) { names.push(files[i].name || files[i].id); }',
|
|
899
|
+
' return names.join(", ");',
|
|
900
|
+
'}',
|
|
901
|
+
'function __poDescribeValue(value) {',
|
|
902
|
+
' if (Array.isArray(value)) { return value.join(", "); }',
|
|
903
|
+
' if (typeof value === "boolean") { return value ? "Yes" : "No"; }',
|
|
904
|
+
' return String(value);',
|
|
905
|
+
'}',
|
|
906
|
+
'function __poSnapshotValue(value) {',
|
|
907
|
+
' if (typeof value === "string" || typeof value === "boolean") { return value; }',
|
|
908
|
+
' if (typeof value === "number") { return isFinite(value) ? value : ""; }',
|
|
909
|
+
' if (Array.isArray(value)) {',
|
|
910
|
+
' var out = [];',
|
|
911
|
+
' for (var i = 0; i < value.length; i++) {',
|
|
912
|
+
' if (typeof value[i] === "string" || (typeof value[i] === "number" && isFinite(value[i]))) { out.push(__poText(value[i])); }',
|
|
913
|
+
' }',
|
|
914
|
+
' return out;',
|
|
915
|
+
' }',
|
|
916
|
+
' return "";',
|
|
917
|
+
'}',
|
|
918
|
+
'function __poParseSnapshot(raw) {',
|
|
919
|
+
' var source = raw;',
|
|
920
|
+
' if (typeof source === "string") {',
|
|
921
|
+
' var trimmed = source.trim();',
|
|
922
|
+
' if (trimmed === "") { return null; }',
|
|
923
|
+
' try { source = JSON.parse(trimmed); } catch (e) { return null; }',
|
|
924
|
+
' }',
|
|
925
|
+
' var entries = [];',
|
|
926
|
+
' var i;',
|
|
927
|
+
' if (__poIsObject(source) && (source.v === 1 || source.v === "1")) {',
|
|
928
|
+
' var list = Array.isArray(source.entries) ? source.entries : [];',
|
|
929
|
+
' for (i = 0; i < list.length; i++) {',
|
|
930
|
+
' var item = list[i];',
|
|
931
|
+
' if (!__poIsObject(item)) { continue; }',
|
|
932
|
+
' var key = __poText(item.key).trim();',
|
|
933
|
+
' if (key === "") { continue; }',
|
|
934
|
+
' var files = __poSafeFiles(item.files);',
|
|
935
|
+
' var value = __poSnapshotValue(item.value);',
|
|
936
|
+
' entries.push({ key: key, label: __poText(item.label) || key, type: __poText(item.type), value: value, valueLabel: __poText(item.valueLabel) || (files.length > 0 ? __poFileNames(files) : __poDescribeValue(value)), priceDelta: __poNullable(item.priceDelta), files: files });',
|
|
937
|
+
' }',
|
|
938
|
+
' return { version: 1, basePrice: __poNullable(source.basePrice), priceDelta: __poNullable(source.priceDelta), entries: entries };',
|
|
939
|
+
' }',
|
|
940
|
+
' if (Array.isArray(source)) {',
|
|
941
|
+
' var parsed = __poParseEntries(source);',
|
|
942
|
+
' for (i = 0; i < parsed.length; i++) {',
|
|
943
|
+
' var legacy = parsed[i].value;',
|
|
944
|
+
' if (Array.isArray(legacy) && legacy.length > 0 && typeof legacy[0] === "object") {',
|
|
945
|
+
' var safe = __poSafeFiles(legacy);',
|
|
946
|
+
' var ids = [];',
|
|
947
|
+
' for (var j = 0; j < safe.length; j++) { ids.push(safe[j].id); }',
|
|
948
|
+
' entries.push({ key: parsed[i].key, label: parsed[i].key, type: "", value: ids, valueLabel: safe.length > 0 ? __poFileNames(safe) : __poDescribeValue(ids), priceDelta: null, files: safe });',
|
|
949
|
+
' } else {',
|
|
950
|
+
' entries.push({ key: parsed[i].key, label: parsed[i].key, type: "", value: legacy, valueLabel: __poDescribeValue(legacy), priceDelta: null, files: [] });',
|
|
951
|
+
' }',
|
|
952
|
+
' }',
|
|
953
|
+
' return { version: 0, basePrice: null, priceDelta: null, entries: entries };',
|
|
954
|
+
' }',
|
|
955
|
+
' return null;',
|
|
956
|
+
'}',
|
|
957
|
+
// Validating: the same issues, in the same order, as validateProductOptionsForProduct.
|
|
958
|
+
'function __poOptionName(label, index, prefix) {',
|
|
959
|
+
' return __poText(label).trim() || prefix + (index + 1);',
|
|
960
|
+
'}',
|
|
961
|
+
'function __poMessage(code, option, source) {',
|
|
962
|
+
' return __poMessages[code].split("{option}").join(option).split("{source}").join(source);',
|
|
963
|
+
'}',
|
|
964
|
+
'function __poIssue(issues, code, target) {',
|
|
965
|
+
' issues.push({ severity: __poWarningCodes.indexOf(code) !== -1 ? "warning" : "error", code: code, message: __poMessage(code, target.option, target.source || ""), groupIndex: target.groupIndex, groupKey: target.groupKey, valueKey: target.valueKey });',
|
|
966
|
+
'}',
|
|
967
|
+
'function __poCheckRule(issues, rule, context) {',
|
|
968
|
+
' if (!__poIsObject(rule)) { return; }',
|
|
969
|
+
' if (rule.mode === "fixed" || rule.mode === "per-unit") {',
|
|
970
|
+
' var amount = __poFinite(rule.amount);',
|
|
971
|
+
' if (amount === undefined || amount < 0 || amount > __poLimits.maxAmount) { __poIssue(issues, "PRICE_AMOUNT_INVALID", context); }',
|
|
972
|
+
' if (rule.mode === "per-unit" && !context.allowPerUnit) { __poIssue(issues, "PRICE_PER_UNIT_NUMBER_ONLY", context); }',
|
|
973
|
+
' } else if (rule.mode === "percent") {',
|
|
974
|
+
' var percent = __poFinite(rule.percent);',
|
|
975
|
+
' if (percent === undefined || percent < 0 || percent > 1000) { __poIssue(issues, "PRICE_PERCENT_RANGE", context); }',
|
|
976
|
+
' }',
|
|
977
|
+
'}',
|
|
978
|
+
'function __poCheckSource(issues, rule, context) {',
|
|
979
|
+
' var codes = context.kind === "price"',
|
|
980
|
+
' ? ["PRICE_SOURCE_MISSING", "PRICE_SOURCE_LATER", "PRICE_SOURCE_TYPE", "PRICE_SOURCE_VALUES"]',
|
|
981
|
+
' : ["VISIBILITY_SOURCE_MISSING", "VISIBILITY_SOURCE_LATER", "VISIBILITY_SOURCE_TYPE", "VISIBILITY_SOURCE_VALUES"];',
|
|
982
|
+
' var sourceIndex = -1;',
|
|
983
|
+
' for (var i = 0; i < context.groups.length; i++) {',
|
|
984
|
+
' if (__poIsObject(context.groups[i]) && context.groups[i].key === rule.groupKey) { sourceIndex = i; break; }',
|
|
985
|
+
' }',
|
|
986
|
+
' if (sourceIndex === -1) { __poIssue(issues, codes[0], context); return; }',
|
|
987
|
+
' var source = context.groups[sourceIndex];',
|
|
988
|
+
' var named = __poWith(context, "source", __poOptionName(source.label, sourceIndex, "Option "));',
|
|
989
|
+
' if (sourceIndex >= context.groupIndex) { __poIssue(issues, codes[1], named); return; }',
|
|
990
|
+
' if (__poSelectableTypes.indexOf(source.type) === -1) { __poIssue(issues, codes[2], named); return; }',
|
|
991
|
+
' if (!context.needsValues) { return; }',
|
|
992
|
+
' var listed = Array.isArray(rule.valueKeys) ? rule.valueKeys : [];',
|
|
993
|
+
' var allowed = __poSourceValueKeys(source);',
|
|
994
|
+
' var bad = listed.length === 0;',
|
|
995
|
+
' for (var j = 0; j < listed.length; j++) { if (allowed.indexOf(listed[j]) === -1) { bad = true; } }',
|
|
996
|
+
' if (bad) { __poIssue(issues, codes[3], named); }',
|
|
997
|
+
'}',
|
|
998
|
+
'function __poCheckOverrides(issues, overrides, context) {',
|
|
999
|
+
' if (!Array.isArray(overrides)) { return; }',
|
|
1000
|
+
' if (overrides.length > __poLimits.priceOverrides) { __poIssue(issues, "PRICE_TOO_MANY_OVERRIDES", context); }',
|
|
1001
|
+
' for (var i = 0; i < overrides.length; i++) {',
|
|
1002
|
+
' var override = overrides[i];',
|
|
1003
|
+
' if (!__poIsObject(override)) { continue; }',
|
|
1004
|
+
' __poCheckSource(issues, override, __poWith(__poWith(context, "kind", "price"), "needsValues", true));',
|
|
1005
|
+
' __poCheckRule(issues, override.price, context);',
|
|
1006
|
+
' }',
|
|
1007
|
+
'}',
|
|
1008
|
+
'function __poCheckValues(issues, group, context) {',
|
|
1009
|
+
' var values = Array.isArray(group.values) ? group.values : [];',
|
|
1010
|
+
' if (values.length === 0) { __poIssue(issues, "CHOICE_NEEDS_VALUE", context); }',
|
|
1011
|
+
' if (values.length > __poLimits.values) { __poIssue(issues, "TOO_MANY_VALUES", context); }',
|
|
1012
|
+
' var seen = [];',
|
|
1013
|
+
' var seenLabels = [];',
|
|
1014
|
+
' var labelMissing = false;',
|
|
1015
|
+
' var labelTooLong = false;',
|
|
1016
|
+
' var labelRepeated = false;',
|
|
1017
|
+
' var defaults = 0;',
|
|
1018
|
+
' for (var i = 0; i < values.length; i++) {',
|
|
1019
|
+
' var value = values[i];',
|
|
1020
|
+
' if (!__poIsObject(value)) { continue; }',
|
|
1021
|
+
' if (value["default"] === true) { defaults += 1; }',
|
|
1022
|
+
' var valueContext = __poWith(context, "valueKey", value.key);',
|
|
1023
|
+
' var label = __poText(value.label).trim();',
|
|
1024
|
+
' if (label === "" && !labelMissing) { __poIssue(issues, "VALUE_LABEL_REQUIRED", valueContext); labelMissing = true; }',
|
|
1025
|
+
' else if (label.length > __poLimits.labelChars && !labelTooLong) { __poIssue(issues, "VALUE_LABEL_TOO_LONG", valueContext); labelTooLong = true; }',
|
|
1026
|
+
' var labelKey = label.toLowerCase();',
|
|
1027
|
+
' if (label !== "" && seenLabels.indexOf(labelKey) !== -1 && !labelRepeated) { __poIssue(issues, "VALUE_LABEL_DUPLICATE", valueContext); labelRepeated = true; }',
|
|
1028
|
+
' if (label !== "") { seenLabels.push(labelKey); }',
|
|
1029
|
+
' if (seen.indexOf(value.key) !== -1) { __poIssue(issues, "DUPLICATE_VALUE_KEY", valueContext); }',
|
|
1030
|
+
' seen.push(value.key);',
|
|
1031
|
+
' __poCheckRule(issues, value.price, valueContext);',
|
|
1032
|
+
' __poCheckOverrides(issues, value.priceWhen, valueContext);',
|
|
1033
|
+
' }',
|
|
1034
|
+
// A required pick-several needs one pick even without a minimum, as the resolver reads it.
|
|
1035
|
+
' if (group.type === "multi-choice" && values.length > 0) {',
|
|
1036
|
+
' var min = Math.max(group.required ? 1 : 0, typeof group.minSelected === "number" ? group.minSelected : 0);',
|
|
1037
|
+
' var max = typeof group.maxSelected === "number" ? group.maxSelected : values.length;',
|
|
1038
|
+
' if (max < 1) { __poIssue(issues, "MULTI_MAX_TOO_LOW", context); }',
|
|
1039
|
+
' else if (min > max) { __poIssue(issues, "MULTI_MIN_MAX", context); }',
|
|
1040
|
+
' else if (min > values.length || max > values.length) { __poIssue(issues, "MULTI_TOO_FEW_VALUES", context); }',
|
|
1041
|
+
// The page would open on these defaults, which the resolver refuses as too many.
|
|
1042
|
+
' else if (defaults > max) { __poIssue(issues, "MULTI_DEFAULTS_TOO_MANY", context); }',
|
|
1043
|
+
' }',
|
|
1044
|
+
'}',
|
|
1045
|
+
'function __poCheckNumber(issues, group, target) {',
|
|
1046
|
+
' var min = typeof group.min === "number" ? group.min : null;',
|
|
1047
|
+
' var max = typeof group.max === "number" ? group.max : null;',
|
|
1048
|
+
' if (min !== null && max !== null && min > max) { __poIssue(issues, "NUMBER_MIN_MAX", target); }',
|
|
1049
|
+
' if (group.step !== undefined && group.step !== null && !(__poSafe(group.step) > 0)) { __poIssue(issues, "NUMBER_STEP", target); }',
|
|
1050
|
+
' var start = typeof group.defaultValue === "number" ? group.defaultValue : null;',
|
|
1051
|
+
' if (start !== null && ((min !== null && start < min) || (max !== null && start > max))) { __poIssue(issues, "NUMBER_DEFAULT_RANGE", target); }',
|
|
1052
|
+
' else if (start !== null && __poOffStep(group.step, group.min, start)) { __poIssue(issues, "NUMBER_DEFAULT_STEP", target); }',
|
|
1053
|
+
'}',
|
|
1054
|
+
// The longest canonical string: text at 2 per character (escapes), an upload at the longest safe ref (2862), a number at 24.
|
|
1055
|
+
'function __poWorstCase(groups) {',
|
|
1056
|
+
' var list = Array.isArray(groups) ? groups : [];',
|
|
1057
|
+
' var total = 2;',
|
|
1058
|
+
' var count = 0;',
|
|
1059
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
1060
|
+
' var group = list[i];',
|
|
1061
|
+
' if (!__poIsObject(group)) { continue; }',
|
|
1062
|
+
' var values = Array.isArray(group.values) ? group.values : [];',
|
|
1063
|
+
' var answer = 0;',
|
|
1064
|
+
' var j;',
|
|
1065
|
+
' if (group.type === "choice") {',
|
|
1066
|
+
' answer = 2;',
|
|
1067
|
+
' for (j = 0; j < values.length; j++) { answer = Math.max(answer, __poText(values[j] && values[j].key).length + 2); }',
|
|
1068
|
+
' } else if (group.type === "multi-choice") {',
|
|
1069
|
+
' answer = 2 + Math.max(0, values.length - 1);',
|
|
1070
|
+
' for (j = 0; j < values.length; j++) { answer += __poText(values[j] && values[j].key).length + 2; }',
|
|
1071
|
+
' } else if (group.type === "text" || group.type === "long-text") {',
|
|
1072
|
+
' var limit = group.type === "text" ? __poLimits.text : __poLimits.longText;',
|
|
1073
|
+
' answer = (typeof group.maxLength === "number" ? Math.min(limit, group.maxLength) : limit) * 2 + 2;',
|
|
1074
|
+
' } else if (group.type === "number") { answer = 24; }',
|
|
1075
|
+
' else if (group.type === "toggle") { answer = 4; }',
|
|
1076
|
+
' else if (group.type === "upload") { answer = 2862; }',
|
|
1077
|
+
' total += 19 + __poText(group.key).length + answer;',
|
|
1078
|
+
' count++;',
|
|
1079
|
+
' }',
|
|
1080
|
+
' return count > 1 ? total + count - 1 : total;',
|
|
1081
|
+
'}',
|
|
1082
|
+
'function __poRuleCharges(rule) {',
|
|
1083
|
+
' if (!__poIsObject(rule)) { return false; }',
|
|
1084
|
+
' if (rule.mode === "fixed" || rule.mode === "per-unit") { return __poSafe(rule.amount) > 0; }',
|
|
1085
|
+
' return rule.mode === "percent" && __poSafe(rule.percent) > 0;',
|
|
1086
|
+
'}',
|
|
1087
|
+
'function __poTargetCharges(target) {',
|
|
1088
|
+
' if (__poRuleCharges(target.price)) { return true; }',
|
|
1089
|
+
' var overrides = Array.isArray(target.priceWhen) ? target.priceWhen : [];',
|
|
1090
|
+
' for (var i = 0; i < overrides.length; i++) { if (__poIsObject(overrides[i]) && __poRuleCharges(overrides[i].price)) { return true; } }',
|
|
1091
|
+
' return false;',
|
|
1092
|
+
'}',
|
|
1093
|
+
'function __poHasPrices(groups) {',
|
|
1094
|
+
' var list = Array.isArray(groups) ? groups : [];',
|
|
1095
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
1096
|
+
' if (!__poIsObject(list[i])) { continue; }',
|
|
1097
|
+
' if (__poTargetCharges(list[i])) { return true; }',
|
|
1098
|
+
' var values = Array.isArray(list[i].values) ? list[i].values : [];',
|
|
1099
|
+
' for (var j = 0; j < values.length; j++) { if (__poIsObject(values[j]) && __poTargetCharges(values[j])) { return true; } }',
|
|
1100
|
+
' }',
|
|
1101
|
+
' return false;',
|
|
1102
|
+
'}',
|
|
1103
|
+
// Also takes validateProductOptionsForProduct's shape: __poValidate(groups, {isGiftCard, paymentType}).
|
|
1104
|
+
'function __poValidate(groups, isGiftCard, paymentType) {',
|
|
1105
|
+
' if (__poIsObject(isGiftCard)) { paymentType = isGiftCard.paymentType; isGiftCard = isGiftCard.isGiftCard; }',
|
|
1106
|
+
' var issues = [];',
|
|
1107
|
+
' var list = Array.isArray(groups) ? groups : [];',
|
|
1108
|
+
' var none = { groupIndex: null, groupKey: null, valueKey: null, option: "" };',
|
|
1109
|
+
' if (list.length > __poLimits.groups) { __poIssue(issues, "TOO_MANY_GROUPS", none); }',
|
|
1110
|
+
' var seenKeys = [];',
|
|
1111
|
+
' for (var i = 0; i < list.length; i++) {',
|
|
1112
|
+
' var group = list[i];',
|
|
1113
|
+
' if (!__poIsObject(group)) { continue; }',
|
|
1114
|
+
' var target = { groupIndex: i, groupKey: group.key, valueKey: null, option: __poOptionName(group.label, i, "Option ") };',
|
|
1115
|
+
' var label = __poText(group.label).trim();',
|
|
1116
|
+
' if (label === "") { __poIssue(issues, "GROUP_LABEL_REQUIRED", target); }',
|
|
1117
|
+
' else if (label.length > __poLimits.labelChars) { __poIssue(issues, "GROUP_LABEL_TOO_LONG", target); }',
|
|
1118
|
+
' if (seenKeys.indexOf(group.key) !== -1) { __poIssue(issues, "DUPLICATE_GROUP_KEY", target); }',
|
|
1119
|
+
' seenKeys.push(group.key);',
|
|
1120
|
+
' var context = __poWith(__poWith(target, "groups", list), "allowPerUnit", false);',
|
|
1121
|
+
' if (__poValueTypes.indexOf(group.type) !== -1) { __poCheckValues(issues, group, context); }',
|
|
1122
|
+
' if (group.type === "text" || group.type === "long-text") {',
|
|
1123
|
+
' var limit = group.type === "text" ? __poLimits.text : __poLimits.longText;',
|
|
1124
|
+
' var maxLength = group.maxLength;',
|
|
1125
|
+
' if (maxLength !== undefined && maxLength !== null && (typeof maxLength !== "number" || Math.floor(maxLength) !== maxLength || maxLength < 1 || maxLength > limit)) {',
|
|
1126
|
+
' __poIssue(issues, group.type === "text" ? "TEXT_MAX_LENGTH" : "LONG_TEXT_MAX_LENGTH", target);',
|
|
1127
|
+
' }',
|
|
1128
|
+
' }',
|
|
1129
|
+
' if (group.type === "number") { __poCheckNumber(issues, group, target); }',
|
|
1130
|
+
' if (__poPricedTypes.indexOf(group.type) !== -1) {',
|
|
1131
|
+
' var priced = __poWith(context, "allowPerUnit", group.type === "number");',
|
|
1132
|
+
' __poCheckRule(issues, group.price, priced);',
|
|
1133
|
+
' __poCheckOverrides(issues, group.priceWhen, priced);',
|
|
1134
|
+
' }',
|
|
1135
|
+
' var rules = Array.isArray(group.visibleWhen) ? group.visibleWhen : [];',
|
|
1136
|
+
' if (rules.length > __poLimits.rules) { __poIssue(issues, "VISIBILITY_TOO_MANY_RULES", target); }',
|
|
1137
|
+
' for (var r = 0; r < rules.length; r++) {',
|
|
1138
|
+
' if (__poIsObject(rules[r])) {',
|
|
1139
|
+
' var needsValues = rules[r].operator === "is" || rules[r].operator === "is-not";',
|
|
1140
|
+
' __poCheckSource(issues, rules[r], __poWith(__poWith(context, "kind", "visibility"), "needsValues", needsValues));',
|
|
1141
|
+
' }',
|
|
1142
|
+
' }',
|
|
1143
|
+
' }',
|
|
1144
|
+
' if (__poWorstCase(list) > __poLimits.configurationChars) { __poIssue(issues, "CONFIGURATION_TOO_LONG", none); }',
|
|
1145
|
+
' var serialized = __poSerialize(list);',
|
|
1146
|
+
' if (serialized !== null && serialized.length > __poLimits.optionGroupsChars) { __poIssue(issues, "OPTION_GROUPS_TOO_LARGE", none); }',
|
|
1147
|
+
' var disabled = __poFlag(isGiftCard) || __poText(paymentType).trim().toLowerCase() === "recurring";',
|
|
1148
|
+
' if (disabled && __poHasPrices(list)) { __poIssue(issues, __poFlag(isGiftCard) ? "GIFT_CARD_OPTIONS_PRICE" : "RECURRING_OPTIONS_PRICE", none); }',
|
|
1149
|
+
' return issues;',
|
|
1150
|
+
'}',
|
|
1151
|
+
exports.PRODUCT_OPTIONS_HELPERS_CLOSING,
|
|
1152
|
+
].join('\n');
|
|
1153
|
+
};
|
|
1154
|
+
exports.generateProductOptionsHelperCode = generateProductOptionsHelperCode;
|
|
1155
|
+
//# sourceMappingURL=product-options.js.map
|