(function(){
var DEBUG = true;
function log(){ if(DEBUG) console.log.apply(console, ["[CALC]"].concat([].slice.call(arguments))); }
function warn(){ console.warn.apply(console, ["[CALC]"].concat([].slice.call(arguments))); }
function err(){ console.error.apply(console, ["[CALC]"].concat([].slice.call(arguments))); }
var providers={"QueryParams":{render:(param)=>{
let { item , state } = param;
if (item.type !== "QueryParams") return null;
try {
var _window_location, _window_history;
if (!(window === null || window === void 0 ? void 0 : (_window_location = window.location) === null || _window_location === void 0 ? void 0 : _window_location.href)) return null;
if (!(window === null || window === void 0 ? void 0 : (_window_history = window.history) === null || _window_history === void 0 ? void 0 : _window_history.replaceState)) return null;
const url = new URL(window.location.href);
let changed = false;
(item.data || []).forEach((row)=>{
var _row_;
const paramKey = String((_row_ = row === null || row === void 0 ? void 0 : row[0]) !== null && _row_ !== void 0 ? _row_ : "").trim();
if (!paramKey) return;
const rawValue = row === null || row === void 0 ? void 0 : row[1];
let nextValue = "";
if (typeof rawValue === "string" && Object.prototype.hasOwnProperty.call(state || {}, rawValue)) {
nextValue = state[rawValue];
} else {
nextValue = rawValue;
}
nextValue = nextValue == null ? "" : String(nextValue);
if (url.searchParams.get(paramKey) !== nextValue) {
url.searchParams.set(paramKey, nextValue);
changed = true;
}
});
if (changed) {
window.history.replaceState(null, "", url.toString());
}
} catch (e) {
console.log("[CALC] QueryParams error", e);
}
return null;
}},"Header":{render:(param)=>{
let { item , h } = param;
if (item.type !== "Header") return null;
const style = {};
if (item.bgColor) {
style.background = item.bgColor;
style.padding = ".5rem .6rem";
style.borderRadius = ".6rem";
}
if (item.textColor) {
style.color = item.textColor;
}
return h("div", {
class: "header",
style
}, item.text || "");
}},"SaveResult":{render:(param)=>{
let { item , h } = param;
if (item.type !== "SaveResult") return null;
const style = {};
if (item.bgColor) style.background = item.bgColor;
if (item.textColor) style.color = item.textColor;
return h("button", {
class: "save-btn",
style,
onMouseEnter: (e)=>{
if (item.hoverBg) e.currentTarget.style.background = item.hoverBg;
},
onMouseLeave: (e)=>{
if (item.bgColor) e.currentTarget.style.background = item.bgColor;
else e.currentTarget.style.background = "";
},
onClick: handleClick
}, item.text || "Скачать");
async function handleClick() {
const root = document.querySelector(".cbs-calc-runtime");
if (!root) return;
try {
const html2canvas = await loadHtml2Canvas();
const calcCanvas = await html2canvas(root, {
backgroundColor: "#ffffff",
useCORS: true
});
const topImg = await loadImage(item.topImage);
const bottomImg = await loadImage(item.bottomImage);
const width = calcCanvas.width;
const topH = topImg ? Math.round(topImg.height * (width / topImg.width)) : 0;
const bottomH = bottomImg ? Math.round(bottomImg.height * (width / bottomImg.width)) : 0;
const height = topH + calcCanvas.height + bottomH;
const finalCanvas = document.createElement("canvas");
finalCanvas.width = width;
finalCanvas.height = height;
const ctx = finalCanvas.getContext("2d");
let y = 0;
if (topImg) {
ctx.drawImage(topImg, 0, y, width, topH);
y += topH;
}
ctx.drawImage(calcCanvas, 0, y);
y += calcCanvas.height;
if (bottomImg) {
ctx.drawImage(bottomImg, 0, y, width, bottomH);
}
const link = document.createElement("a");
link.download = "result.png";
link.href = finalCanvas.toDataURL("image/png");
link.click();
} catch (e) {
console.error(e);
alert("Ошибка сохранения");
}
}
function loadImage(src) {
return new Promise((res)=>{
if (!src) return res(null);
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = ()=>res(img);
img.onerror = ()=>res(null);
img.src = src;
});
}
function loadHtml2Canvas() {
if (window.html2canvas) return Promise.resolve(window.html2canvas);
return new Promise((resolve, reject)=>{
const s = document.createElement("script");
s.src = "https://unpkg.com/html2canvas@1.4.1/dist/html2canvas.min.js";
s.onload = ()=>resolve(window.html2canvas);
s.onerror = reject;
document.head.appendChild(s);
});
}
}},"Image":{render:(param)=>{
let { item , h } = param;
if (item.type !== "Image") return null;
if (!item.src) return null;
let aspectClass = "";
if (item.aspect === "wide") aspectClass = "image-wide";
else if (item.aspect === "square") aspectClass = "image-square";
else aspectClass = "image-free";
const imgClass = item.aspect ? "image" : "image";
return h("div", {
class: "image-wrap " + aspectClass
}, h("img", {
class: imgClass,
src: item.src
}));
}},"Text":{render:(param)=>{
let { item , h } = param;
if (item.type !== "Text") return null;
if (!item.text) return null;
const parts = String(item.text).split(/\n+/);
return h("div", {
class: "text-block"
}, parts.map((line)=>h("p", {}, line)));
}},"DataSelect":{render:(param)=>{
let { item , state , set , get , h } = param;
if (item.type !== "DataSelect") return null;
let data = {};
try {
data = JSON.parse(item.data || "{}");
} catch (e) {}
const keys = Object.keys(data || {});
const def = item.default || keys[0] || "";
const value = get(item.key, def);
const row = data[value];
if (row && typeof row === "object") {
Object.entries(row).forEach((param)=>{
let [k, v] = param;
set(k, v);
});
}
return h("div", {
class: "field"
}, item.name ? h("div", {
class: "field-label"
}, item.name) : null, h("select", {
value: value || "",
onChange: (e)=>set(item.key, e.target.value)
}, keys.map((k)=>h("option", {
value: k
}, k))));
}},"Input":{render:(param)=>{
let { item , state , set , get , h } = param;
if (item.type !== "Input") return null;
var _item_default;
const value = get(item.key, (_item_default = item.default) !== null && _item_default !== void 0 ? _item_default : 0);
return h("div", {
class: "field"
}, item.name ? h("div", {
class: "field-label"
}, item.name) : null, h("input", {
value: value !== null && value !== void 0 ? value : "",
onInput: (e)=>set(item.key, parseFloat(e.target.value) || 0)
}));
}},"Select":{render:(param)=>{
let { item , state , set , get , h } = param;
var _item_variants, _item_variants_;
if (item.type !== "Select") return null;
var _item_variants__value, _item_default;
const def = (_item_default = item.default) !== null && _item_default !== void 0 ? _item_default : (_item_variants__value = (_item_variants = item.variants) === null || _item_variants === void 0 ? void 0 : (_item_variants_ = _item_variants[0]) === null || _item_variants_ === void 0 ? void 0 : _item_variants_.value) !== null && _item_variants__value !== void 0 ? _item_variants__value : 0;
const value = get(item.key, def);
return h("div", {
class: "field"
}, item.name ? h("div", {
class: "field-label"
}, item.name) : null, h("select", {
value,
onChange: (e)=>set(item.key, parseFloat(e.target.value) || 0)
}, (item.variants || []).map((v)=>h("option", {
value: v.value
}, v.name))));
}},"Radio":{render:(param)=>{
let { item , state , set , get , h } = param;
var _item_variants, _item_variants_;
if (item.type !== "Radio") return null;
var _item_variants__value, _item_default;
const def = (_item_default = item.default) !== null && _item_default !== void 0 ? _item_default : (_item_variants__value = (_item_variants = item.variants) === null || _item_variants === void 0 ? void 0 : (_item_variants_ = _item_variants[0]) === null || _item_variants_ === void 0 ? void 0 : _item_variants_.value) !== null && _item_variants__value !== void 0 ? _item_variants__value : 0;
const value = get(item.key, def);
return h("div", {}, item.name ? h("div", {
class: "field-label"
}, item.name) : null, h("div", {
class: "radio-group",
style: {
gridTemplateColumns: "repeat(" + (item.cols || 4) + ",1fr)"
}
}, (item.variants || []).map((v)=>{
const ratioClass = v.imageRatio === "wide" ? "radio-ratio-wide" : v.imageRatio === "square" ? "radio-ratio-square" : "";
return h("div", {
class: "radio-card" + (value === v.value ? " active" : ""),
onClick: ()=>set(item.key, v.value)
}, v.image ? h("img", {
class: "radio-img " + ratioClass,
src: v.image
}) : null, h("div", {
class: "radio-card-label"
}, v.name));
})));
}},"Calc":{render:(param)=>{
let { item , calc , set } = param;
if (item.type !== "Calc") return null;
const v = calc(item.formula || "");
set(item.key, v);
return null;
}},"Range":{render:(param)=>{
let { item , state , set , get , h } = param;
if (item.type !== "Range") return null;
var _item_min;
const min = Number((_item_min = item.min) !== null && _item_min !== void 0 ? _item_min : 0);
var _item_max;
const max = Number((_item_max = item.max) !== null && _item_max !== void 0 ? _item_max : 100);
var _item_step;
const step = Number((_item_step = item.step) !== null && _item_step !== void 0 ? _item_step : 1);
var _item_default;
const def = (_item_default = item.default) !== null && _item_default !== void 0 ? _item_default : min;
const stateValue = get(item.key, def);
const snapped = normalize(stateValue, min, max, step);
const inputValue = clampEdge(snapped, min, max, step);
return h("div", {
class: "field"
}, h("div", {
class: "range-head"
}, item.name ? h("div", {
class: "field-label"
}, item.name) : h("div", {}), h("div", {
class: "range-value"
}, inputValue)), h("input", {
type: "range",
class: "range-input",
min: min,
max: max,
step: "any",
value: inputValue,
onInput: (e)=>{
const raw = parseFloat(e.target.value) || 0;
const v = normalize(raw, min, max, step);
set(item.key, v);
}
}));
function normalize(v, min, max, step) {
if (v <= min) return min;
if (v >= max) return max;
const steps = Math.round((v - min) / step);
let snapped = min + steps * step;
return Number(snapped.toFixed(6));
}
function clampEdge(v, min, max, step) {
if (Math.abs(v - min) <= step) return min;
if (Math.abs(v - max) <= step) return max;
return v;
}
}},"Result":{render:(param)=>{
let { item , state , h } = param;
if (item.type !== "Result") return null;
const rows = [];
(item.data || []).forEach((row)=>{
const cols = (row || []).map((cell)=>{
const val = state[cell];
if (isFinite(val)) {
const n = Number(val);
const out = Number.isInteger(n) ? n : Number(n.toFixed(2));
return h("td", {}, out);
}
return h("td", {}, cell);
});
rows.push(h("tr", {}, cols));
});
return h("div", {
class: "results-card"
}, item.title ? h("div", {
class: "header"
}, item.title) : null, h("table", {}, rows));
}}};
var PREACT_URL='https://unpkg.com/preact@10.19.3/dist/preact.umd.js';
var HOOKS_URL='https://unpkg.com/preact@10.19.3/hooks/dist/hooks.umd.js';
function showError(container,title,text){
if(!container) return;
container.innerHTML="";
var wrap=document.createElement("div");
wrap.className="calc-error";
var h=document.createElement("div");
h.className="calc-error-title";
h.textContent=title || "Ошибка";
var ta=document.createElement("textarea");
ta.value=text || "";
wrap.appendChild(h);
wrap.appendChild(ta);
container.appendChild(wrap);
}
function load(src){
return new Promise(function(res,rej){
var s=document.createElement('script');
s.src=src;
s.onload=res;
s.onerror=function(e){
rej(e);
};
document.head.appendChild(s);
});
}
function calcExpr(expr,state){
try{
if(!expr) return 0;
if(expr[0]==='=') expr = expr.slice(1);
var keys=Object.keys(state||{});
var vals=keys.map(function(k){return state[k];});
return Function.apply(null, keys.concat(["return "+expr])).apply(null, vals);
}catch(e){
err("CALC ERROR", expr, e);
return 0;
}
}
function extractDeps(expr){
if(!expr) return [];
if(expr[0]==='=') expr = expr.slice(1);
var m = expr.match(/[A-Z]+[0-9_]+/g);
return m || [];
}
function detectCycles(elements){
var graph={};
var keys={};
for(var i=0;i0;
});
if(!cols.length) return null;
var content = h('div',{class:'grid'},
cols.map(function(col,c){ return renderCol(col,c); })
);
var viewMode = block && block.viewMode ? block.viewMode : "full";
if(viewMode === "dropdown"){
var style={};
if(block.dropdownBg) style.background=block.dropdownBg;
if(block.dropdownColor) style.color=block.dropdownColor;
return h('details',{key:i},
h('summary',{style:style},
block.dropdownTitle || "Подробнее"
),
content
);
}
return h('div',{class:'grid',key:i},
cols.map(function(col,c){ return renderCol(col,c); })
);
}
var layout=(schema && schema.layout) ? schema.layout : [];
return h('div',{class:'cbs-calc-runtime'},
layout.map(function(b,i){ return renderBlock(b,i); })
);
}
try{
render(h(App),container);
}catch(e){
err("Render crash", e);
showError(container,"Ошибка рендера схемы",e.stack || e.message);
}
}
(function init(){
var p = Promise.resolve();
if(!window.preact) p = p.then(function(){ return load(PREACT_URL); });
if(!window.preactHooks) p = p.then(function(){ return load(HOOKS_URL); });
p.then(start).catch(function(e){
var container=document.getElementById('data-calc');
if(container){
showError(container,"Ошибка рендера схемы",e.stack || e.message);
}
err("Init failed", e);
});
})();
})();
Lorem ipsum
test
Показать калькулятор