PageSourceSearch

https://iampho.ru/var/cache/asset20_914e8f163f5183761dd7b4f6d3bca47c.js

js iampho.ru collected 2026-10-07 18:09:48 UTC 61,559 bytes, 883 lines download raw bytes

1app.overlapIndicatorComponent={props:['value'],data(){this.observer=null;return{}},mounted(){this.observer=new IntersectionObserver(([e])=>{this.$emit('input',e.intersectionRatio<1)},{threshold:1});this.observer.observe(this.$refs.indicator)},beforeDestroy(){this.observer.unobserve(this.$refs.indicator)},template:`
2    <div ref="indicator"></div>
3    `};app.tpNutrientsComponent={props:['isApp','nutrients','sizes','loc'],data:function(){return{popupVisible:!1}},computed:{title:function(){return this.loc['topping/nutrients/title']},visible(){if(this.isApp){return this.nutrients&&this.nutrients.default}
4return this.nutrients&&this.nutrients.default&&this.nutrients.default.length},selectedNutrients(){return app.tpSizesAvailability.bySize(this.nutrients,this.sizes.selected)},processedNutrients(){const groups=[{title:this.title,items:[]}];let shortGroup=null;for(const item of this.selectedNutrients){const value=item.value+(item.unit?' '+item.unit:'');if(value.length>20){groups.push({title:item.name,items:[{value}]});shortGroup=null;continue}
5if(!shortGroup){shortGroup={title:'',items:[]};groups.push(shortGroup)}
6shortGroup.items.push({name:item.name,value})}
7return groups}},methods:{show:function(){if(!this.popupVisible){this.popupVisible=!0}}},directives:{close:{bind:function(el,binding,vnode){el.clickOutsideFn=function(){vnode.context.popupVisible=!1}
8setTimeout(function(){document.body.addEventListener('click',el.clickOutsideFn)},30)},unbind:function(el){document.body.removeEventListener('click',el.clickOutsideFn)}}},template:`
9    <div v-if="visible"
10         class="nutr">
11
12        <div v-if="popupVisible"
13             class="nutr__popup-wrap"
14             v-close>
15            <div class="nutr__popup">
16
17                <template v-if="isApp">
18                    <template v-for="group in processedNutrients">
19                        <div v-if="group.title" class="nutr__title">{{group.title}}</div>
20                        <div v-for="item in group.items" class="nutr__item">
21                            <div v-if="item.name" class="nutr__name">{{item.name}}</div>
22                            <div class="nutr__value">{{item.value}}</div>
23                        </div>
24                    </template>
25                </template>
26
27                <template v-else>
28                    <div class="nutr__title">{{title}}</div>
29
30                    <div v-for="item in selectedNutrients"
31                         class="nutr__item">
32                        <div class="nutr__name">{{item.name}}</div>
33                        <div class="nutr__value">{{item.value}}{{item.unit ? ' ' + item.unit : ''}}</div>
34                    </div>
35                </template>
36
37            </div>
38        </div>
39
40        <i @click="show()"
41           class="nutr__ico">
42            <svg class="nutr__svg" width="3" height="11" viewBox="0 0 3 11">
43                <path fill-rule="evenodd" clip-rule="evenodd" d="M1.44001 2.744C2.12042 2.744 2.67201 2.19241 2.67201 1.512C2.67201 0.831584 2.12042 0.279999 1.44001 0.279999C0.759593 0.279999 0.208008 0.831584 0.208008 1.512C0.208008 2.19241 0.759593 2.744 1.44001 2.744ZM2.34001 10.84V4.68H0.540008V10.84H2.34001Z" fill="#3D3D3D"/>
44            </svg>
45            <svg v-if="!isApp" class="nutr__svgDesktop" xmlns="http://www.w3.org/2000/svg" width="2" height="10" viewBox="0 0 2 10" fill="none">
46                <rect y="4" width="2" height="6" rx="1" fill="#555454"/>
47                <rect width="2" height="2" rx="1" fill="#555454"/>
48            </svg>
49        </i>
50
51    </div>
52    `};app.tpParamsComponent={props:['isApp','dish','sizes'],computed:{params:function(){return app.tpSizesAvailability.visibleParams(this.dish,this.sizes.selected)}},template:`
53    <div v-if="params.length" class="tpar">
54
55        <div v-for="param in params"
56             class="tpar__item">
57            <template v-if="isApp">
58                <span class="tpar__name">{{param.name}}</span>
59                <span class="tpar__dots"></span>
60                <span class="tpar__value">{{param.value}}</span>
61            </template>
62            <template v-else>
63                <b>{{param.name}}:</b> {{param.value}}
64            </template>
65        </div>
66
67    </div>
68    `};app.tpIngredientsComponent={components:{'tp-nutrients':app.tpNutrientsComponent,'tp-params':app.tpParamsComponent},props:['isApp','isDesktopVersion','dish','sizes','modifiers','loc','company',],data(){let collapsed=!1;if(this.isApp){const hasText=!!this.dish.ingredients;const isTextLong=hasText&&this.dish.ingredients.length>=200;const hasParams=hasText&&app.tpSizesAvailability.visibleParams(this.dish,this.sizes.selected).length>0;collapsed=isTextLong||hasParams;if(!this.sizes.options.length&&!this.modifiers.length){collapsed=!1}}
69return{isCollapsible:collapsed,collapsed:collapsed}},computed:{allergensLink(){return this.company&&this.company.allergensLink},locAllergensLink(){return this.loc['ingredients/allergens']},dishName(){if(!app.tpSizesAvailability.hasSwitcher(this.sizes.options)){return null}
70return this.dish.name},pricePerUnit(){const size=this.sizes.selected;const partial=this.dish.prices&&this.dish.prices[size]&&this.dish.prices[size].partialConfig;if(!partial||!partial.displayPerUnit||!partial.priceOneUnit||!partial.sizeTypeFormatted){return null}
71return{price:partial.priceOneUnitFormatted,size:'1 '+partial.sizeTypeFormatted}},ingredients(){if(!this.dish.ingredients){return null}
72const text=this.dish.ingredients;if(!this.isApp){return text.replace(/\n/g,'<br>')}
73return this.collapsed?text:text.replace(/\n/g,'<br> ')},composition(){const composition=this.dish.ingredients2;if(typeof composition==='string'){return composition}
74return app.tpSizesAvailability.bySize(composition,this.sizes.selected)||''},locComposition(){return this.loc['dish/param/ingredients']}},methods:{toggleCollapsed(){if(this.isCollapsible){this.collapsed=!this.collapsed}},navigateAllergens(){this.$emit('openLink',this.allergensLink)}},template:`
75    <div class="ingr__wrap">
76
77        <tp-nutrients v-if="!isDesktopVersion"
78                      :isApp="isApp"
79                      :nutrients="dish.nutrients"
80                      :sizes="sizes"
81                      :loc="loc"/>
82
83        <div v-if="dishName" class="ingr__dish">
84            {{dishName}}
85            <tp-nutrients v-if="isDesktopVersion"
86                          :isApp="isApp"
87                          :nutrients="dish.nutrients"
88                          :sizes="sizes"
89                          :loc="loc"/>
90        </div>
91
92        <div v-if="pricePerUnit" class="ingr__pricePerUnit">
93            {{pricePerUnit.price}}<span class="ingr__pricePerUnit-size">{{pricePerUnit.size}}</span>
94        </div>
95
96        <div v-if="ingredients && isApp" class="ingr">
97
98            <div class="ingr__text"
99                 v-html="ingredients"
100                 @click="toggleCollapsed"
101                 :class="{'ingr__text--collapsed': collapsed}"></div>
102
103        </div>
104
105        <div v-if="ingredients && !isApp" class="ingr" v-html="ingredients"></div>
106
107        <tp-params v-if="isApp && !collapsed"
108                   :isApp="isApp"
109                   :dish="dish"
110                   :sizes="sizes"/>
111
112        <div v-if="composition && isApp" class="ingr__composition">
113            <b>{{locComposition}}:</b> {{composition}}
114        </div>
115
116        <div v-if="composition && !isApp" class="ingr2">
117            {{composition}}
118        </div>
119
120        <div v-if="allergensLink && isApp" class="ingr__allergensLink" @click="navigateAllergens()">
121            {{ locAllergensLink }}
122        </div>
123
124        <a v-if="allergensLink && !isApp" class="ingr__allergensLink" :href="allergensLink" target="_blank">
125            {{ locAllergensLink }}
126        </a>
127    </div>
128    `};app.tpSizesAvailability={isAvailable(option){return!!option&&option.price!=='-'},visibleOptions(options){return(options||[]).filter(option=>this.isAvailable(option))},selectPos(options,selected){const visible=this.visibleOptions(options).filter(option=>typeof option.pos==='number');if(visible.some(option=>option.pos===selected)){return selected}
129return visible.length?visible[0].pos:0},pointerIndex(options,selected){const index=this.visibleOptions(options).findIndex(option=>option.pos===selected);return index===-1?0:index},hasSwitcher(options){return this.visibleOptions(options).length>1}
129,bySize(map,pos){return map?(map[pos]||map.default):undefined},visibleParams(dish,pos){const grouped=[];const indexByName=Object.create(null);(this.bySize(dish.params,pos)||[]).forEach(param=>{const name=param.name!=null?String(param.name):'';const value=param.value!=null?String(param.value).trim():'';if(!value){return}
130if(indexByName[name]===undefined){indexByName[name]=grouped.length;grouped.push(Object.assign({},param,{value}));return}
131grouped[indexByName[name]].value+=', '+value});return grouped},sizePack(sizes,pos){const option=sizes&&sizes.options&&sizes.options[pos];return(option&&option.modifiers)||null},pack(dishModifiers,pos){const modifiers=(this.sizePack(dishModifiers[0],pos)||dishModifiers.slice(1)).slice();modifiers.sort((a,b)=>{const aPos=a.required?-1:a.pos;const bPos=b.required?-1:b.pos;if(aPos===bPos){return 0}
132return aPos<bPos?-1:1});return modifiers},selectedPack(dishModifiers){const sizes=dishModifiers[0];return this.pack(dishModifiers,this.selectPos(sizes&&sizes.options,sizes&&sizes.selected))},isWithPoints(isApp,dish,pos){if(isApp){return dish.restrictions&&dish.restrictions.dishesWithPoints}
133return dish.prices&&dish.prices[pos]&&dish.prices[pos].isWithPoints},hasPointsMinSum(isApp,dish){if(isApp){return!!(dish.restrictions&&dish.restrictions.dishesWithPointsMinSum)}
134return Object.keys(dish.prices||{}).some(pos=>!!(this.isWithPoints(!1,dish,pos)&&dish.prices[pos].pointDishMinSum))},};app.tpSizesComponent={components:{'tp-ingredients':app.tpIngredientsComponent,'tp-nutrients':app.tpNutrientsComponent,pointIcon:app.pointIconComponent,},props:['isApp','isDesktopVersion','dish','sizes','modifiers','loc','company','hidePrice',],created(){const pos=app.tpSizesAvailability.selectPos(this.sizes.options,this.sizes.selected);if(this.sizes.selected!==pos){this.$set(this.sizes,'selected',pos)}},computed:{visibleSizeOptions(){return app.tpSizesAvailability.visibleOptions(this.sizes.options)},rowLimit(){return this.isApp?3:5},isMany(){return this.isApp&&this.visibleSizeOptions.length>=4},isLargeItems(){return!this.isApp&&this.visibleSizeOptions.length>=5},isGrid(){return this.isLargeItems&&this.isDesktopVersion},pointerStyle(){if(this.isGrid){return}
135const x=app.tpSizesAvailability.pointerIndex(this.sizes.options,this.sizes.selected)*100;return{"-webkit-transform":"translateX("+x+"%)",transform:this.isApp?"translate3d("+x+"%, 0, 0)":"translateX("+x+"%)"}},bgStyle(){if(this.isGrid){return}
136const len=this.visibleSizeOptions.length;return{width:len<=this.rowLimit?'100%':'calc(30% * '+len+')'}},optionStyle(){const len=this.visibleSizeOptions.length;return{width:len<=this.rowLimit?'calc(100% / '+len+')':'30%'}},info(){if(this.optionsVisible){return null}
137if(this.isApp){return{name:this.dish.name,price:this.dish.price,priceFrom:this.dish.priceFrom||'',size:this.dish.size}}
138const size=this.dish.size||'';const weight=size.split('|')[0].trim();const name=String(this.dish.name);const cutName=weight&&name.endsWith(weight)&&name.slice(0,-weight.length).trim();return{name:cutName||this.dish.name,price:this.dish.price,size:size}},optionsVisible(){return app.tpSizesAvailability.hasSwitcher(this.sizes.options)},options(){const options=[];this.sizes.options.forEach((option,i)=>{if(!app.tpSizesAvailability.isAvailable(option)){return}
139let price=app.tpSizesAvailability.isWithPoints(this.isApp,this.dish,i)?this.priceFormat(option.price):option.priceFormatted;if(!this.isApp&&this.visibleSizeOptions.length===4){price=price.replace('руб.','р.')}
140options.push({pos:option.pos,price:price,size:option.size,balance:this.balanceFormat(option.balance),active:option.pos===this.sizes.selected,withPointer:options.length===0})});return options},isWithPoints(){return app.tpSizesAvailability.isWithPoints(this.isApp,this.dish,this.sizes.selected)},},methods:{select(option){if(this.sizes.selected!==option.pos){this.$emit('haptics')}
141this.sizes.selected=option.pos},priceFormat(value){return app.price.format(value,'',this.company.priceSeparator)},balanceFormat(balance){if(!balance){return''}
142const unit=(this.loc&&this.loc['unit/count'])||'';return(balance+' '+unit).trim()},},template:`
143    <div class="tsizes">
144
145        <div v-if="info && isApp" class="tsizes__infoWrap">
146
147            <div class="tsizes__info">
148
149                <div class="tsizes__info-name">
150                    {{info.name}}&nbsp;&nbsp;<span v-if="info.size" class="tsizes__info-size">{{info.size}}</span>
151                </div>
152                <div v-if="!hidePrice" class="tsizes__info-price">
153                    {{info.priceFrom ? info.priceFrom : info.price}}
154                    <point-icon v-if="isWithPoints" class="hIcon__point" variant="cart"></point-icon>
155                </div>
156
157            </div>
158
159            <tp-ingredients :isApp="isApp"
160                            :dish="dish"
161                            :sizes="sizes"
162                            :modifiers="modifiers"
163                            :loc="loc"
164                            :company="company"
165                            @openLink="$emit('openLink', $event)"/>
166
167        </div>
168
169        <template v-if="info && !isApp">
170
171            <div class="tsizes__info">
172
173                <div class="tsizes__info-name">
174                    {{info.name}}
175                    <tp-nutrients v-if="isDesktopVersion"
176                                  :isApp="isApp"
177                                  :nutrients="dish.nutrients"
178                                  :sizes="sizes"
179                                  :loc="loc"/>
180                </div>
181                <div class="tsizes__info-price">
182                    {{info.price}}
183                    <svg v-if="isWithPoints" class="tp__pointIcon">
184                        <use xlink:href="#tp__pointIcon"></use>
185                    </svg>
186
187                    <span v-if="info.size" class="tsizes__info-size">{{info.size}}</span>
188                </div>
189
190            </div>
191
192            <tp-ingredients :isApp="isApp"
193                            :isDesktopVersion="isDesktopVersion"
194                            :dish="dish"
195                            :sizes="sizes"
196                            :modifiers="modifiers"
197                            :loc="loc"
198                            :company="company"/>
199
200        </template>
201
202        <div v-if="optionsVisible" class="tsizes__scrollable" :class="{'tsizes__scrollable--many': isMany}">
203
204            <div class="tsizes__options" :class="{'tsizes__options--large': isLargeItems}">
205
206                <div class="tsizes__bg" :style="bgStyle"></div>
207
208                <div v-for="option in options"
209                     :key="option.pos"
210                     class="tsizes__option"
211                     :style="optionStyle"
212                     @click="select(option)"
213                     :class="{'tsizes__option--active': option.active}">
214
215                    <div class="tsizes__content">
216                        <div class="tsizes__price">
217                            {{option.price}}
218                            <point-icon v-if="isApp && isWithPoints" class="hIcon__point" variant="cart"></point-icon>
219                            <svg v-if="!isApp && isWithPoints" class="tp__pointIcon">
220                                <use xlink:href="#tp__pointIcon"></use>
221                            </svg>
222                        </div>
223                        <div v-if="option.size" class="tsizes__size" v-html="option.size"></div>
224                        <div v-if="option.balance" class="tsizes__balance">{{option.balance}}</div>
225                    </div>
226
227                    <div v-if="option.withPointer"
228                         class="tsizes__pointer"
229                         :style="pointerStyle"></div>
230
231                </div>
232
233            </div>
234
235        </div>
236
237    </div>
238    `};app.tpOptionManyboxComponent={props:['count','price','isAppearanceTiles'],computed:{value(){return this.count||this.price},isEmpty(){return!this.count}},methods:{onMinus:function(){this.$emit('minus')}},template:`
239    <div class="tpmanybox" :class="{'tpmanybox--tiles': isAppearanceTiles, 'tpmanybox--empty': isEmpty}">
240        <div class="tpmanybox__minus" @click.stop="onMinus()"></div>
241        <div class="tpmanybox__count">{{value}}</div>
242        <div class="tpmanybox__plus"></div>
243    </div>
244    `};app.tpOptionComponent={props:['isApp','option','modifier','sizes','isAppearanceTiles','isAddressOk'],components:{Manybox:app.tpOptionManyboxComponent},created(){if(!this.option.count){this.$set(this.option,'count',parseInt(this.option.defaultAmount)||0)}
245if(this.isCustom){this.$watch('sizes.selected',function(pos,prevPos){pos=this.resolvePricePos(pos);if(this.isNoPriceAt(pos)){this.$set(this.option,'count',0)}else if(prevPos!==undefined&&this.isNoPriceAt(this.resolvePricePos(prevPos))){this.applyDefaultAmount()}
246this.$set(this.option,'pos',pos)},{immediate:!0})}
247if(this.isRequired&&this.option.id===this.modifier.options[0].id){this.$watch('modifier.options',function(options){if(!this.countInModifier&&!this.countDefaultInModifier){options[0].count=1}},{immediate:!0,deep:!0})}},computed:{photo(){return this.option.photo},isPhotoSlot(){if(this.isApp){return!!this.photo}
248return!!this.modifier.options.find(option=>!!option.photo)},isRequired:function(){return this.modifier.required},isManyMany:function(){return this.modifier.type==='many_many'},isOneOne:function(){if(this.modifier.max&&this.modifier.max===1){return!0}
249return this.modifier.type==='one_one'},isCustom:function(){return this.modifier.custom},isVisible(){const isNoPrice=this.isCustom&&this.option.prices[this.option.pos].price==='-';const isHidden=isNoPrice||this.option.isService;this.option.isHidden=isHidden;return!isHidden},isManybox:function(){return this.isAppearanceTiles||(this.isManyMany&&this.count>0&&this.limitCount>1)},limitCount:function(){if(this.isOneOne){return 1}
250if(this.option.max){return this.option.max}
251if(this.modifier.max){return this.modifier.max}
252if(this.isCustom){return 1}
253if(!this.option.price){return 1}
254return this.option.prices.length>1?this.option.prices.length:99},isSelected:function(){return this.option.count>0},size:function(){return this.isCustom?this.option.prices[this.option.pos].sizeFormatted:this.option.sizeFormatted},name:function(){return this.option.name+(this.size?', '+this.size:'')},isPriceVisible(){return!this.isAppearanceTiles},price(){var p=this.isCustom?this.option.prices[this.option.pos]:this.option;if(!this.isApp&&!Object.keys(p).find(function(k){return k==='priceFormatted'})){p.priceFormatted=p.price_formatted}
255return p.price?'+'+p.priceFormatted:p.priceFormatted},count(){return this.option.count},countInModifier(){var count=0;for(var i=0;i<this.modifier.options.length;i++){var modifier=this.modifier.options[i];if(modifier.count){count+=modifier.count}}
256return count},countDefaultInModifier(){var count=0;for(var i=0;i<this.modifier.options.length;i++){var modifier=this.modifier.options[i];if(modifier.defaultAmount){count+=modifier.defaultAmount}}
257return count},isModifierMaxReached(){if(this.isOneOne){return!1}
258return this.modifier.max&&this.countInModifier>=this.modifier.max},issetEmptyOptions(){return!!this.modifier.options.find(option=>!option.count)},isMinReached(){const min=parseInt(this.option.min||0);if(this.count<=min){return!0}
259if(min===1&&this.isRequired){return!0}
260return!1},},methods:{resolvePricePos(pos){return this.option.prices[pos]?pos:0},isNoPriceAt(pos){return this.option.prices[pos].price==='-'},applyDefaultAmount(){const amount=parseInt(this.option.defaultAmount)||0;if(!amount||this.option.count){return}
261const isGroupFull=this.isOneOne?this.countInModifier>0:this.modifier.max&&this.countInModifier+amount>this.modifier.max;if(!isGroupFull){this.$set(this.option,'count',amount)}},onMinus(){if(this.isApp&&!this.isAddressOk()){return}
262if(this.option.min&&this.count<=this.option.min){return}
263if(this.count){this.option.count--;this.$emit('haptics')}},onPlus(){if(this.isApp&&!this.isAddressOk()){return}
264if(this.isModifierMaxReached){if(this.isManyMany&&this.limitCount===1&&this.isSelected&&this.issetEmptyOptions){this.option.count=0}else if(!this.isMinReached){this.option.count=0}
265return}
266this.$emit('haptics');if(this.isOneOne){if(this.isSelected){if(!this.isRequired&&!this.isAppearanceTiles){this.option.count=0}}else{this.option.count=1;for(var i=0;i<this.modifier.options.length;i++){var modOpt=this.modifier.options[i];if(modOpt.count&&modOpt.id!==this.option.id){modOpt.count=0}}}}else if(this.isManyMany&&this.limitCount>1){if(this.count<this.limitCount){this.option.count++}}else if(this.isManyMany&&this.limitCount===1){if(this.isSelected){if(!this.option.min||this.count>this.option.min){this.option.count=0}}else{this.option.count=1}}}},template:`
267    
268    <div v-if="isVisible"
269         class="topt"
270         :class="{'topt--max-reached': isModifierMaxReached, 'topt--selected': count, 'topt--tiles': isAppearanceTiles}"
271         @click="onPlus()">
272
273        <div v-if="isPhotoSlot" class="topt__photoWrap">
274            <img v-if="photo" class="topt__photo" alt="" :src="photo">
275            <svg v-else width="35" height="35" viewBox="0 0 35 35" fill="none">
276                <rect width="35" height="35" rx="6" fill="black" fill-opacity="0.05"/>
277                <path d="M35 0L31.3238 -1.60692e-07L-8.92369e-07 31.3238L-1.05306e-06 35L3.67621 35L35 3.67622L35 0ZM35 9.17535L9.17535 35L16.524 35L35 16.524L35 9.17535ZM35 22.0231L22.0231 35L29.3755 35L35 29.3755L35 22.0231ZM25.8247 -4.01067e-07L18.476 -7.22286e-07L-3.30775e-07 18.476L-6.51994e-07 25.8247L25.8247 -4.01067e-07ZM12.9769 -9.62661e-07L5.62446 -1.28405e-06L2.30984e-07 5.62446L-9.04006e-08 12.9769L12.9769 -9.62661e-07Z" fill="white"/>
278            </svg>
279        </div>
280
281
282        <div class="topt__name">
283            <span class="topt__name-wrap">{{name}}</span>
284            <span v-if="isPriceVisible" class="topt__price">{{price}}</span>
285        </div>
286
287        <Manybox v-if="isManybox"
288                 :count="count"
289                 :price="price"
290                 :isAppearanceTiles="isAppearanceTiles"
291                 @minus="onMinus()"/>
292
293        <!-- tpcheckbox--isOneOne: сайт рисует one_one круглым (checkbox.css), в приложении правила нет -->
294        <div v-else
295             class="tpcheckbox"
296             :class="{'tpcheckbox--selected': isSelected, 'tpcheckbox--isOneOne': !isApp && isOneOne}"></div>
297
298
299    </div>
300    
301    `};app.tpModifierComponent={components:{'tp-option':app.tpOptionComponent},props:['isApp','modifier','sizes','loc','isAppearanceTiles','isAddressOk'],data(){return{isVisible:!0}},mounted(){setTimeout(()=>{let allOptionsSet=!0;for(let i=0;i<this.options.length;i++){const option=this.options[i];
301if(!option.min||!option.max||!option.count||option.min!==option.max||option.min!==option.count){allOptionsSet=!1;break}}
302if(allOptionsSet){this.isVisible=!1}},50)},watch:{'options':{handler(options){this.$nextTick(()=>{let isHidden=!0;options.forEach(option=>{if(!option.isHidden){isHidden=!1}});this.isVisible=!isHidden})},deep:!0}},computed:{title(){return this.modifier.title},subTitle(){if(this.modifier.max){return `${this.loc['topping/max']}: ${this.modifier.max}`}
303return null},options:function(){return this.modifier.options||[]}},template:`
304    <div v-show="isVisible" class="tmod">
305
306        <div class="tmod__title">{{title}}</div>
307
308        <div v-if="subTitle" class="tmod__subTitle">{{subTitle}}</div>
309
310        <div class="tmod__options" :class="{'tmod__options--tiles': isAppearanceTiles}">
311
312            <tp-option v-for="(option, i) in options"
313                       :key="i"
314                       :isApp="isApp"
315                       :modifier="modifier"
316                       :option="option"
317                       :sizes="sizes"
318                       :isAppearanceTiles="isAppearanceTiles"
319                       :isAddressOk="isAddressOk"
320                       @haptics="$emit('haptics')">
321            </tp-option>
322
323            <div v-if="isAppearanceTiles" class="tmod__dummy"></div>
324
325        </div>
326
327
328    </div>
329    `};app.tpQuarterPartComponent={props:['isApp','part','sizes'],computed:{style:function(){var src=this.isApp?'https://v8.foodpicasso.com/assets/home4/topping4/info/quarter/main/i/bg.png':'/assets/modules/topping/info/quarter/main/i/bg.png';for(var i=0;i<this.part.options.length;i++){var option=this.part.options[i];if(option.count){src=option.photoPart}}
330return{backgroundImage:'url('+src+')'}},type:function(){return this.part.quarterType}},methods:{navigate:function(){this.$emit('open',{part:this.part,pos:this.sizes.selected})}},template:`
331    <div class="tpart"
332         :class="'tpart--'+type"
333         :style="style" @click="navigate()">
334    </div>
335    `};app.tpQuarterComponent={components:{'quarter-part':app.tpQuarterPartComponent},props:['isApp','modifiers','sizes','company'],computed:{rotateQuarter:function(){return this.isApp&&this.company&&this.company.rotateQuarter},parts:function(){return(this.modifiers||[]).filter(modifier=>modifier.quarterType)}},template:`
336    <div class="tpcn"
337         :class="{'tpcn--rotate': rotateQuarter}">
338
339        <div class="tpcn__content">
340            <quarter-part v-for="part in parts"
341                          :isApp="isApp"
342                          :part="part"
343                          :sizes="sizes"
344                          @open="$emit('openPart', $event)"/>
345        </div>
346
347    </div>
348    `};app.tpQuarterRule={isActive(modifiers){if(!app.tpQuarterComponent){return!1}
349const types=new Set((modifiers||[]).map(modifier=>modifier.quarterType).filter(Boolean));let quarters=0;let halfs=0;types.forEach(type=>{if(type.includes('quarter')){quarters++}else if(type.includes('half')){halfs++}});return(quarters===4&&halfs===0)||(halfs===2&&quarters===0)}};app.tpInfoComponent={components:{'tp-quarter':app.tpQuarterComponent,'tp-ingredients':app.tpIngredientsComponent,},props:['isApp','isDesktopVersion','dish','sizes','modifiers','isQuarterActive','loc','company',],data:function(){return{activeImage:0}},computed:{isImageVisible(){return!this.isDesktopVersion},ingredientsVisible:function(){return app.tpSizesAvailability.hasSwitcher(this.sizes.options)},media(){if(this.dish.media&&this.dish.media.length){return this.dish.media}
350if(!this.isApp){return[{high:'/assets/modules/topping/info/main/i/empty.png',low:'',ratio:'60.07',empty:!0}]}
351if(this.dish.photo){return[this.dish.photo,...(this.dish.extraPhotos||[])].map(photo=>({full:photo.full,ratio:photo.ratio||80,low:photo.low||'',}))}
352return[{full:'https://v8.foodpicasso.com/assets/home4/topping4/info/main/i/empty.png',low:'',ratio:'60.07'}]},mediaRatio(){return Math.max(...this.media.map((media)=>media.ratio||80))}},methods:{onScrollImages(){const scrollable=this.$refs.scrollable;this.activeImage=Math.round(scrollable.scrollLeft/scrollable.clientWidth)||0}},template:`
353    <div class="tinf">
354
355        <template v-if="isImageVisible">
356
357            <tp-quarter v-if="isQuarterActive"
358                        :isApp="isApp"
359                        :modifiers="modifiers"
360                        :sizes="sizes"
361                        :company="company"
362                        @openPart="$emit('openPart', $event)"/>
363
364            <div v-else class="tinf__images">
365
366                <div class="tinf__scrollable"
367                     ref="scrollable"
368                     @scroll="onScrollImages()">
369                    <div v-for="image of media"
370                         class="tinf__image-wrap"
371                         :class="{lazyload__wrap: !isApp}"
372                         :style="{paddingBottom: mediaRatio + '%'}">
373
374                        <template v-if="image.type === 'video'">
375                            <video class="tinf__image tinf__image--video"
376                                   :src="image.preview"
377                                   autoplay muted loop playsinline webkit-playsinline></video>
378                        </template>
379
380                        <img v-else-if="isApp"
381                             :src="image.full"
382                             alt=""
383                             class="tinf__image">
384
385                        <!-- Сайт грузит фото через lazysizes: сначала low, потом high -->
386                        <img v-else
387                             :data-src="image.high"
388                             :data-lowsrc="image.low"
389                             :src="image.empty ? image.high : ''"
390                             alt=""
391                             class="tinf__image"
392                             :class="{'tinf__image--empty': image.empty, lazyload: !image.empty}">
393
394                    </div>
395
396                </div>
397
398                <template v-if="media.length > 1">
399                    <div v-if="!isApp" class="tinf__bulletsShadow"></div>
400                    <div class="tinf__bullets">
401                        <i v-for="(image, i) in media"
402                           class="tinf__bullet"
403                           :class="{'tinf__bullet--active': i === activeImage}"></i>
404                    </div>
405                </template>
406
407            </div>
408
409        </template>
410
411        <div v-if="ingredientsVisible"
412             class="tinf__ingredients">
413            <tp-ingredients :isApp="isApp"
414                            :isDesktopVersion="isDesktopVersion"
415                            :dish="dish"
416                            :sizes="sizes"
417                            :modifiers="modifiers"
418                            :loc="loc"
419                            :company="company"
420                            @openLink="$emit('openLink', $event)"/>
421        </div>
422
423    </div>
424    `};app.tpSubmitComponent={components:{partialWeight:app.partialWeightComponent,animatedCount:app.commonAnimatedCountComponent,pointIcon:app.pointIconComponent,}
424,props:['isApp','dish','sizes','modifiers','dishSectionId','loc','company','cart','isAppearanceInput','forceRemoveDish','isAddressOk','hideCount','hidePrice','submitText','combo','issetRestriction','userHasToSubscribe','shadow',],data(){return{partialWeight:null}},watch:{partialWeight(newWeight){if(!this.isPartialWithSizes||!newWeight){return}
425var weights=this.sizeWeights;var options=this.sizes.options;var visible=app.tpSizesAvailability.visibleOptions(options);var bestIndex=visible.length?visible[0].pos:0;for(var i=weights.length-1;i>=0;i--){if(weights[i]>0&&newWeight>=weights[i]&&app.tpSizesAvailability.isAvailable(options[i])){bestIndex=i;break}}
426if(this.sizes.selected!==bestIndex){this._skipSizeWatch=!0;this.sizes.selected=bestIndex}},'sizes.selected':function(newIndex){if(!this.isPartialWithSizes){return}
427if(this._skipSizeWatch){this._skipSizeWatch=!1;return}
428var weight=this.sizeWeights[newIndex];if(weight>0){this.partialWeight=weight}}},created(){if(!this.dish.count){this.$set(this.dish,'count',1)}
429this.partialWeight=this.partial&&this.partial.defaultWeight;this._skipSizeWatch=!1},computed:{buttonState(){if(this.dish.isStop){return'stop'}
430if(this.dish.orderScheduleStop){return'schedule'}
431if(this.pointDishBlocked){return'pointMin'}
432return'add'},isBlocked(){return this.buttonState==='stop'||this.buttonState==='schedule'},isQrReadonly(){return!this.isApp&&this.company&&this.company.isQrReadonly},isCounterVisible(){return!this.hideCount&&!this.isQrReadonly&&(this.buttonState==='add'||this.buttonState==='stop')},orderScheduleText:function(){return this.dish.orderScheduleLabel||''},count(){return this.dish.count},selectedSizeOption(){const sizes=this.sizes||{};const option=(sizes.options||[])[sizes.selected];return(option&&option.dishId)?option:null},dishBalance(){const option=this.selectedSizeOption;return option?option.balance:this.dish.balance},customModifierPos(){return this.selectedSizeOption?0:this.sizes.selected},balance:function(){if(this.isBlocked){return null}
433var balance=this.dishBalance;if(!balance){return null}
434return `${this.loc['topping/remains']} ${balance} ${this.loc['unit/count']}`},minusInactive(){if(this.partial){var minWeight=this.partialMinWeight;return this.partialWeight<=minWeight}
435return this.count<=1},plusInactive(){const balance=this.dishBalance;if(balance&&this.count>=balance){return!0}
436if(this.partial){return this.partialWeight>=9999}},dishPrice(){const size=this.sizes.selected;return(this.dish.prices&&this.dish.prices[size])||{}},partial(){return this.dishPrice.partialConfig},isPartialWithSizes(){return this.partial&&this.sizes.options&&this.sizes.options.length>1},sizeWeights(){if(!this.sizes.options||!this.sizes.options.length){return[]}
437return this.sizes.options.map(function(opt){return parseFloat(opt.size)||0})},partialMinWeight(){if(!this.partial){return 0}
438return this.partial.defaultWeight||(this.isPartialWithSizes&&this.sizeWeights[0])||0},isWithPoints(){return app.tpSizesAvailability.isWithPoints(this.isApp,this.dish,this.sizes.selected)},pointDishMinSum(){if(this.isApp){return(this.dish.restrictions&&this.dish.restrictions.dishesWithPointsMinSum)||0}
439return(this.isWithPoints&&this.dishPrice.pointDishMinSum)||0},pointDishBlocked(){if(!this.pointDishMinSum){return!1}
440const amount=this.cart&&this.cart.amount;return((amount&&amount.pointDishRegularSum)||0)<this.pointDishMinSum},pointDishMinSumText(){if(this.isApp){return(this.dish.restrictions&&this.dish.restrictions.dishesWithPointsHint)||''}
441return(this.isWithPoints&&this.dishPrice.pointDishHint)||''},total(){const size=this.sizes.selected;const modifierSize=this.customModifierPos;const base=this.isApp?this.dishPrice:this.sizes.options&&this.sizes.options[size];let startPrice=base&&base.price;if(!app.tpSizesAvailability.isAvailable(base)){startPrice=0}
442if(this.partial){startPrice=this.partial.priceOneUnit*this.partialWeight}
443let total=startPrice||0;let separateTotal=0;for(let i=0;i<this.modifiers.length;i++){let modifier=this.modifiers[i];for(let j=0;j<modifier.options.length;j++){let option=modifier.options[j];if(option.isHidden&&!option.isService){continue}
444if(!option.count){continue}
445let price=option.price;if(modifier.custom){if(!option.prices[modifierSize]){this.$emit('alert',{message:"Invalid modifier configuration: all modifier prices should be tied to the dish size",kind:'config'});return"Error"}
446price=option.prices[modifierSize].price}
447if(typeof(price)!=='number'){continue}
448if(modifier.isSeparate){separateTotal+=price*option.count}else{total+=price*option.count}}}
449if(this.combo){total+=this.combo.filter(Boolean).reduce((sum,dish)=>sum+dish.dishTotal,0)}
450total=total*this.count+separateTotal;const currency=this.isWithPoints?'':(this.isApp?this.company.rub:this.company.currency);return app.price.format(total,currency,this.company.priceSeparator)}},methods:{changeCount(type){if(this.isApp&&!this.isAddressOk()){return}
451if(this.isBlocked){return}
452if(type==='plus'){this.increase()}else{this.decrease()}},increase(){if(this.plusInactive){return}
453if(this.partial){const newWeight=(Math.round(this.partialWeight*1000)+Math.round(this.partial.partialStep*1000))/1000;this.partialWeight=newWeight>9999?9999:newWeight;return}else{this.dish.count++}
454this.$emit('haptics')},decrease(){const isRaiseToMin=!this.isApp&&this.partial;if(this.minusInactive&&!isRaiseToMin){return}
455if(this.partial){var minWeight=this.partialMinWeight;const newWeight=(Math.round(this.partialWeight*1000)-Math.round(this.partial.partialStep*1000))/1000;this.partialWeight=newWeight<minWeight?minWeight:newWeight;return}else{this.dish.count=Math.max(this.dish.count-1,0)}
456this.$emit('haptics')},submit(){if(this.partial){var minWeight=this.partialMinWeight;if(this.partialWeight<minWeight){this.partialWeight=minWeight;return}}
457if(this.isQrReadonly){this.$emit('callWaiter');return}
458if(!this.isAddressOk()){return}
459if(this.issetRestriction){return}
460if(this.buttonState!=='add'){return}
461const sizeOption=this.selectedSizeOption;const dishId=sizeOption?sizeOption.dishId:this.dish.id;const size=(sizeOption||this.isPartialWithSizes)?0:this.sizes.selected;const options=[];let total=this.dish.priceRaw;for(let i=0;i<this.modifiers.length;i++){let modifier=this.modifiers[i];if(this.isApp&&modifier.type==='combo'){continue}
462let modifierActiveOptionsCount=0;let modifierHiddenOptionsCount=0;for(let j=0;j<modifier.options.length;j++){let option=modifier.options[j];if(option.isHidden&&!option.isService){modifierHiddenOptionsCount++;continue}
463if(!option.count){continue}
464modifierActiveOptionsCount+=option.count;options.push({id:option.id,idWithSize:option.id+(option.pos?'_'+option.pos:'')+'x'+option.count});total+=option.price*option.count}
465if(modifier.options.length!==modifierHiddenOptionsCount){if(modifier.min&&modifierActiveOptionsCount<modifier.min){let err=this.loc['topping/err/minOptions'].replace('{section}',modifier.title);let optionsLoc=this.loc['topping/option2'].split('|');err=err.replace('{options}',modifier.min+' '+app.plural(modifier.min,optionsLoc[0],optionsLoc[1],optionsLoc[2]))
466this.$emit('alert',{message:err,kind:'minOptions'});return}}}
467if(options.length){options.sort(function(a,b){return parseInt(a.id)<parseInt(b.id)?-1:1});for(let i in options){options[i]=options[i].idWithSize}}
468const dishSelected=dishId+'_'+size+(options.length?'+'+options.join(','):'');this.$emit('submit',{count:this.dish.count,dishId:this.dish.id,dishPos:dishSelected,dishName:this.dish.name,dishTotal:total,sectionId:this.dishSectionId,forceRemoveDish:this.forceRemoveDish,addWeight:this.partial&&this.partialWeight})}},template:`
469<div v-if="!userHasToSubscribe"
470     class="tsubmit"
471     :class="{'tsubmit--shadow': shadow, 'tsubmit--stop': buttonState === 'stop', 'tsubmit--orderSchedule': buttonState === 'schedule', 'tsubmit--pointDishMinSum': buttonState === 'pointMin'}">
472
473    <div v-if="balance"
474         class="tsubmit__balance">
475        {{balance}}
476    </div>
477
478    <div class="tsubmit__buttons">
479
480        <div v-if="isCounterVisible" class="tsubmit__counter">
481
482            <div class="tsubmit__minus"
483                 :class="{'tsubmit__minus--inactive': minusInactive}"
484                 v-tp-press
485                 @click="changeCount('minus')"></div>
486
487
488            <div v-if="partial" class="tsubmit__partial">
489
490                <partialWeight v-model="partialWeight"
491                               :readonly="!isAppearanceInput"
492                               :unit="partial.sizeTypeFormatted"
493                               :min="partialMinWeight"
494                               :max="9999"/>
495
496            </div>
497            <input v-else-if="isAppearanceInput"
498                   class="tsubmit__count tsubmit__count--input"
499                   v-model="dish.count">
500            <div v-else class="tsubmit__count tsubmit__count--animated">
501                <animatedCount :value="count"/>
502            </div>
503
504            <div class="tsubmit__plus"
505                 :class="{'tsubmit__plus--inactive': plusInactive}"
506                 v-tp-press
507                 @click="changeCount('plus')"></div>
508        </div>
509
510        <div class="tsubmit__button" v-tp-press @click="submit()">
511
512            <template v-if="isQrReadonly">
513                {{ loc['site/qrMenu/callWaiter'] }}
514            </template>
515
516            <template v-else-if="buttonState === 'schedule'">
517                <div class="tsubmit__text tsubmit__text--orderSchedule">{{ orderScheduleText }}</div>
518            </template>
519
520            <template v-else-if="isApp && buttonState === 'stop'">
521                {{ loc['dish/na'] }}
522            </template>
523
524            <template v-else-if="buttonState === 'pointMin'">
525                <div class="tsubmit__text tsubmit__text--pointDishMinSum">{{ pointDishMinSumText }}</div>
526            </template>
527
528            <template v-else>
529                <div class="tsubmit__text">{{ submitText || loc['topping/add'] }}</div>
530                <svg v-if="!hidePrice" class="tsubmit__delimiter" width="2" height="20" viewBox="0 0 2 20" fill="none" xmlns="http://www.w3.org/2000/svg">
531                    <line x1="0.865723" y1="0.590576" x2="0.865722" y2="18.5906" stroke="currentColor" stroke-linecap="round" stroke-dasharray="1 4"/>
532                </svg>
533                <div v-if="!hidePrice" class="tsubmit__total">
534                    {{ total }}
535                    <svg v-if="!isApp && isWithPoints" class="tp__pointIcon">
536                        <use xlink:href="#tp__pointIcon"></use>
537                    </svg>
538                </div>
539                <point-icon v-if="isApp && isWithPoints" class="tsubmit__point hIcon__point" variant="cart"></point-icon>
540            </template>
541
542        </div>
543
544    </div>
545
546</div>
547    `};app.tpImageComponent={inject:['store','loc'],data(){this.swiper=null;return{}},computed:{textFormatted(){return this.loc['site/topping/emptyImage/promise'].replaceAll('\n','<br>')},media(){if(!this.store.dish.media||!this.store.dish.media.length){return null}
548return this.store.dish.media},},mounted(){if(!this.media){return}
549this.swiper=new Swiper(this.$refs.container,{direction:'horizontal',slidesPerView:1,spaceBetween:0,grabCursor:this.media.length>1,loop:this.media.length>1,pagination:{el:this.$refs.pagination,clickable:!0,},navigation:{nextEl:this.$refs.next,prevEl:this.$refs.prev,disabledClass:'tpImage__nav--disabled'},allowTouchMove:!0,})},beforeDestroy(){},destroyed(){this.swiper&&this.swiper.destroy()},template:`
550<div class="tpImage" :class="{'tpImage--slider': media}">
551
552    <div v-if="!media"
553         class="tpImage__empty">
554        <div class="tpImage__stub">
555            <svg class="tpImage__serenity" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">
556                <path d="M40.4895 46.7656L34.2343 40.5626C31.2159 37.5693 29.7066 36.0726 27.9746 35.5255C26.4514 35.0442 24.8143 35.0619 23.3018 35.576C21.582 36.1605 20.1055 37.6895 17.1526 40.7474L2.16536 55.5505M40.4895 46.7656L41.7697 45.4961C44.7919 42.4991 46.3029 41.0006 48.0367 40.4537C49.5615 39.9727 51.2001 39.9915 52.7134 40.5075C54.4341 41.0941 55.9104 42.627 58.8628 45.6927L62 48.8504M40.4895 46.7656L55.5311 61.837M55.5311 61.837C54.1909 62 52.4538 62 50 62H14C9.7996 62 7.69941 62 6.09507 61.1826C4.68386 60.4635 3.5365 59.3161 2.81745 57.9049C2.47986 57.2424 2.28169 56.4952 2.16536 55.5505M55.5311 61.837C56.485 61.721 57.2378 61.5225 57.9049 61.1826C59.3161 60.4635 60.4635 59.3161 61.1826 57.9049C62 56.3006 62 54.2004 62 50V48.8504M2.16536 55.5505C2 54.2077 2 52.4657 2 50V14C2 9.79961 2 7.69941 2.81745 6.09507C3.5365 4.68386 4.68386 3.5365 6.09507 2.81745C7.69941 2 9.7996 2 14 2H50C54.2004 2 56.3006 2 57.9049 2.81745C59.3161 3.5365 60.4635 4.68386 61.1826 6.09507C62 7.69941 62 9.79961 62 14V48.8504M50.75 20.7496C50.75 24.8917 47.3921 28.2496 43.25 28.2496C39.1079 28.2496 35.75 24.8917 35.75 20.7496C35.75 16.6075 39.1079 13.2496 43.25 13.2496C47.3921 13.2496 50.75 16.6075 50.75 20.7496Z" stroke="black" stroke-opacity="0.3" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round"/>
557            </svg>
558            <div class="tpImage__caption">{{ loc['site/topping/emptyImage/caption'] }}</div>
559        </div>
560        <div class="tpImage__text" v-html="textFormatted"></div>
561    </div>
562
563    <div v-else ref="container" class="tpImage__container swiper">
564
565        <div class="tpImage__wrapper swiper-wrapper">
566
567            <div v-for="(image, idx) in media"
568                 class="tpImage__slide swiper-slide lazyload__wrap">
569
570                <template v-if="image.type === 'video'">
571                    <video class="tpImage__img tpImage__img--video"
572                           :src="image.preview"
573                           autoplay muted loop playsinline webkit-playsinline></video>
574                </template>
575
576                <img v-else
577                     :data-src="image.high"
578                     :data-lowsrc="image.low"
579                     :data-position="idx"
580                     :src="image.low"
581                     alt=""
582                     class="tpImage__img lazyload"/>
583
584            </div>
585
586        </div>
587        
588        <div ref="pagination"
589             class="tpImage__pagination swiper-pagination">   
590        </div>
591
592        <div ref="prev" class="tpImage__nav"><svg><use xlink:href="#icon__arrow"></use></svg></div>
593        <div ref="next" class="tpImage__nav"><svg><use xlink:href="#icon__arrow"></use></svg></div>
594
595    </div>
596
597
598</div>
599    `};app.tpCardComponent={components:{'tp-info':app.tpInfoComponent,'tp-sizes':app.tpSizesComponent,'tp-params':app.tpParamsComponent,'tp-modifier':app.tpModifierComponent,'tp-submit':app.tpSubmitComponent,}
599,props:['isApp','isDesktopVersion','dish','dishModifiers','loc','company','cart','isAppearanceTiles','isAppearanceInput','isAddressOk','dishSectionId','forceRemoveDish','hidePrice','hideCount','submitText','combo','issetRestriction','userHasToSubscribe','shadow',],data(){return{modifiersRevision:0}},watch:{'sizes.selected':function(pos,old){if(!app.tpSizesAvailability.sizePack(this.sizes,pos)){return}
600const prev=app.tpSizesAvailability.pack(this.dishModifiers,app.tpSizesAvailability.selectPos(this.sizes.options,old));this.carryModifierCounts(prev,this.modifiers);this.modifiersRevision++}},computed:{sizes(){return this.dishModifiers[0]},modifiers(){return app.tpSizesAvailability.selectedPack(this.dishModifiers)},quarterModifiers(){return this.isApp?this.modifiers:this.dishModifiers},isQuarterActive(){return app.tpQuarterRule.isActive(this.quarterModifiers)}},methods:{carryModifierCounts(from,to){const counts={};from.forEach(modifier=>(modifier.options||[]).forEach(option=>{if(option.count){counts[modifier.sectionId+':'+option.id]=option.count}}));to.forEach(modifier=>(modifier.options||[]).forEach(option=>{const carried=counts[modifier.sectionId+':'+option.id];if(carried){this.$set(option,'count',carried)}}))}},template:`
601    <div v-if="isApp" class="tpDish">
602
603        <div class="tpDish__wrap">
604
605            <slot name="beforeInfo"></slot>
606
607            <tp-info :isApp="true"
608                     :dish="dish"
609                     :sizes="sizes"
610                     :modifiers="quarterModifiers"
611                     :isQuarterActive="isQuarterActive"
612                     :loc="loc"
613                     :company="company"
614                     @openLink="$emit('openLink', $event)"
615                     @openPart="$emit('openPart', $event)"/>
616
617            <slot name="afterInfo"></slot>
618
619            <div class="tpDish__content">
620
621                <tp-sizes v-if="sizes"
622                          :isApp="true"
623                          :dish="dish"
624                          :sizes="sizes"
625                          :modifiers="modifiers"
626                          :loc="loc"
627                          :company="company"
628                          :hidePrice="hidePrice"
629                          @haptics="$emit('haptics')"
630                          @openLink="$emit('openLink', $event)"/>
631
632                <div v-if="combo" class="tpDish__combo">
633                    <slot name="combo" :modifiers="modifiers"></slot>
634                </div>
635
636                <div v-else class="tpDish__modifiers">
637                    <tp-modifier
638                        v-for="(modifier, i) in modifiers"
639                        :key="modifiersRevision + '_' + i"
640                        :isApp="true"
641                        :modifier="modifier"
642                        :sizes="sizes"
643                        :loc="loc"
644                        :isAppearanceTiles="isAppearanceTiles"
645                        :isAddressOk="isAddressOk"
646                        @haptics="$emit('haptics')"
647                    />
648                </div>
649
650            </div>
651
652            <tp-submit
653                :isApp="true"
654                :dish="dish"
655                :sizes="sizes"
656                :modifiers="modifiers"
657                :dishSectionId="dishSectionId"
658                :loc="loc"
659                :company="company"
660                :cart="cart"
661                :isAppearanceInput="isAppearanceInput"
662                :forceRemoveDish="forceRemoveDish"
663                :isAddressOk="isAddressOk"
664                :issetRestriction="issetRestriction"
665                :hideCount="hideCount"
666                :hidePrice="hidePrice"
667                :submitText="submitText"
668                :combo="combo"
669                @submit="$emit('submit', $event)"
670                @haptics="$emit('haptics')"
671                @alert="$emit('alert', $event)"
672            />
673
674        </div>
675
676    </div>
677
678    <div v-else class="tp" :class="{'tp--quarter': isQuarterActive}">
679
680        <svg xmlns="http://www.w3.org/2000/svg" style="display: none">
681            <symbol id="icon__arrow" viewBox="0 0 9 15" xmlns="http://www.w3.org/2000/svg">
682                <path d="M7.85501 14.509L9.00001 13.349L2.90601 7.254L9.00001 1.16L7.85501 0L0.600006 7.255L7.85501 14.509Z" fill="currentColor"/>
683            </symbol>
684            <symbol id="tp__pointIcon" width="16" height="14" viewBox="0 0 16 14" fill="none">
685                <path d="M6.5 1.25C9.67564 1.25 12.25 3.82436 12.25 7C12.25 10.1756 9.67564 12.75 6.5 12.75C3.32436 12.75 0.75 10.1756 0.75 7C0.75 3.82436 3.32436 1.25 6.5 1.25Z" stroke="currentColor" stroke-width="1.5"/>
686                <path d="M11.0867 13.1664C13.0422 11.7611 14.3164 9.46186 14.3164 6.86393C14.3164 4.22779 13.0044 1.89919 11 0.5C13.7024 1.33499 15.6666 3.86075 15.6666 6.84694C15.6666 9.80109 13.7444 12.3046 11.0867 13.1664Z" fill="currentColor"/>
687            </symbol>
688        </svg>
689
690        <!-- Десктоп сайта: слева четвертинки или галерея, их рисует вход -->
691        <slot name="aside" :isQuarterActive="isQuarterActive"></slot>
692
693        <div class="tp__data">
694
695            <tp-info
696                :isApp="false"
697                :isDesktopVersion="isDesktopVersion"
698                :dish="dish"
699                :sizes="sizes"
700                :modifiers="quarterModifiers"
701                :isQuarterActive="isQuarterActive"
702                :loc="loc"
703                :company="company"/>
704
705            <div class="tp__content">
706
707                <tp-sizes
708                    :isApp="false"
709                    :isDesktopVersion="isDesktopVersion"
710                    :dish="dish"
711                    :sizes="sizes"
712                    :loc="loc"
713                    :company="company"/>
714
715                <tp-params
716                    :isApp="false"
717                    :dish="dish"
718                    :sizes="sizes"/>
719
720                <tp-modifier
721                    v-for="(modifier, i) in modifiers"
722                    :key="modifiersRevision + '_' + i"
723                    :isApp="false"
724                    :modifier="modifier"
725                    :sizes="sizes"
726                    :loc="loc"
727                    :isAppearanceTiles="isAppearanceTiles"/>
728
729                <slot name="afterModifiers"></slot>
730            </div>
731
732        </div>
733
734        <tp-submit
735            :isApp="false"
736            :dish="dish"
737            :sizes="sizes"
738            :modifiers="modifiers"
739            :loc="loc"
740            :company="company"
741            :cart="cart"
742            :isAppearanceInput="isAppearanceInput"
743            :isAddressOk="isAddressOk"
744            :userHasToSubscribe="userHasToSubscribe"
745            :shadow="shadow"
746            @submit="$emit('submit', $event)"
747            @callWaiter="$emit('callWaiter')"
748            @alert="$emit('alert', $event)"/>
749
750    </div>
751    `};app.tpSiteAlert=function({message,kind}
751){if(kind==='config'){alert(message);return}
752app.alert(message,'danger')};Vue.directive('tp-press',{});app.addModule(function(){const show=(vrParams)=>{let vr;const runVm=(params)=>{const toppingComponent={components:Object.assign({'tp-card':app.tpCardComponent,'tp-image':app.tpImageComponent,'tp-quarter':app.tpQuarterComponent,'overlap-indicator':app.overlapIndicatorComponent,},app.siteDishFavComponent?{'site-dish-fav':app.siteDishFavComponent}:{}),provide(){return{store:this.store,loc:this.loc}},data(){return{store:{isAppearanceTiles:this.$store.state.company&&this.$store.state.company.toppingAppearance==='tiles',isAppearanceInput:this.$store.state.company&&this.$store.state.company.toppingCounterAppearance==='input',dish:params.dish,modifiers:params.modifiers,forceAddress:params.forceAddress,forceRemoveDish:params.forceRemoveDish},isOverlap:!1}},computed:Object.assign({sizes(){return this.store.modifiers[0]},isDesktopVersion(){return this.isKiosk||!this.mobile},isFav(){return!this.isDesktopVersion&&!!app.siteFav&&app.siteFav.state.ready},modifiers(){return app.tpSizesAvailability.selectedPack(this.store.modifiers)},pointsCart(){return app.tpSizesAvailability.hasPointsMinSum(!1,this.store.dish)?this.cart:null}},Vuex.mapState(['loc','mobile','isKiosk','company','cart','userHasToSubscribe'])),mounted(){this.$nextTick(()=>{this.restoreSelections()})},methods:{callWaiter(){setTimeout(()=>{PubSub.publish('showWaiter',{action:'call-waiter'})},600);this.$emit('close')},onSubmit(selected){PubSub.publish('dishSelected',{dishPosId:selected.dishPos,count:selected.count,addWeight:selected.addWeight,forceRemoveDish:this.store.forceRemoveDish,});this.$emit('close')},onAlert(e){app.tpSiteAlert(e)},isAddressOk(){if(this.store.forceAddress){var selections={sizeSelected:this.sizes.selected,modifiers:{},count:this.store.dish.count||1};this.modifiers.forEach(function(mod){(mod.options||[]).forEach(function(opt){if(opt.count&&opt.count!==(parseInt(opt.defaultAmount)||0)){selections.modifiers[opt.id]=opt.count}})});sessionStorage.setItem('restoreToppingSelections',JSON.stringify(selections));PubSub.publish(this.store.forceAddress,{forceReload:!0,openDishAfterReload:{id:this.store.dish.id,name:this.store.dish.name}});return!1}
753return!0},restoreSelections(){var raw=sessionStorage.getItem('restoreToppingSelections');if(!raw)return;sessionStorage.removeItem('restoreToppingSelections');var selections=JSON.parse(raw);if(selections.modifiers){this.modifiers.forEach(function(mod){(mod.options||[]).forEach(function(opt){if(selections.modifiers[opt.id]!==undefined){opt.count=selections.modifiers[opt.id]}})})}
754if(selections.sizeSelected!==undefined){this.sizes.selected=app.tpSizesAvailability.selectPos(this.sizes.options,selections.sizeSelected)}
755if(selections.count>1){this.$set(this.store.dish,'count',selections.count)}}},template:`
756
757                <tp-card
758                    :isApp="false"
759                    :isDesktopVersion="isDesktopVersion"
760                    :dish="store.dish"
761                    :dishModifiers="store.modifiers"
762                    :loc="loc"
763                    :company="company"
764                    :cart="pointsCart"
765                    :isAppearanceTiles="store.isAppearanceTiles"
766                    :isAppearanceInput="store.isAppearanceInput"
767                    :isAddressOk="isAddressOk"
768                    :userHasToSubscribe="userHasToSubscribe"
769                    :shadow="isOverlap"
770                    @submit="onSubmit"
771                    @callWaiter="callWaiter"
772                    @alert="onAlert">
773
774                    <template #aside="{isQuarterActive}">
775                        <template v-if="isDesktopVersion">
776                            <tp-quarter v-if="isQuarterActive"
777                                class="tp__quarter"
778                                :isApp="false"
779                                :modifiers="store.modifiers"
780                                :sizes="sizes"/>
781
782                            <tp-image v-else
783                                class="tp__image"/>
784                        </template>
785
786                        <site-dish-fav v-else-if="isFav"
787                            :dishId="Number(store.dish.id)"
788                            size="big"
789                            place="card"/>
790                    </template>
791
792                    <template #afterModifiers>
793                        <overlap-indicator
794                            v-if="isDesktopVersion"
795                            v-model="isOverlap"/>
796                    </template>
797
798                </tp-card>
799
800            `};app.openViewer({desktop:{maxWidth:'1050px',disableAutogrow:!0,overflow:'hidden',},mobile:{withTick:!0,withClose:!1,minHeight:'90dvh',maxHeight:'90dvh',backgroundColor:'transparent',},className:'tp__viewer',component:toppingComponent,})}
801if(vrParams.preload){app.fetch('/cart/topping/get',vrParams.preload,(response)=>{if(response.error){return vr.close()}
802runVm(response)})}else{runVm(vrParams)}};const tryToOpenDishAfterReload=()=>{const openDishAfterReload=sessionStorage.getItem('openDishAfterReload');if(!openDishAfterReload){return}
803sessionStorage.removeItem('openDishAfterReload');const dish=JSON.parse(openDishAfterReload);let dishEl=document.querySelector('.ddish[data-id="'+dish.id+'"]');if(!dishEl){dishEl=Array.from(document.querySelectorAll('.ddish__link')).find(item=>item.innerText===dish.name);
803dishEl=dishEl&&dishEl.closest('.ddish')}
804if(!dishEl){return}
805PubSub.publish('hydrateDish',{id:dishEl.dataset.id,plusClicked:!1});if(!app.hydrateMenuDish&&!dishEl.classList.contains('ddish--observed')){dishEl.click()}}
806PubSub.subscribe('showTopping',(e,params)=>{show(params);if(params.dish){PubSub.publish('gtmNotify',{event:'view_item',item:params.dish})}});setTimeout(()=>{tryToOpenDishAfterReload()},300)});app.tpShellComponent={components:{'tp-info':app.tpInfoComponent,'tp-sizes':app.tpSizesComponent,'tp-params':app.tpParamsComponent,'tp-modifier':app.tpModifierComponent,'tp-submit':app.tpSubmitComponent,'tp-image':app.tpImageComponent,'overlap-indicator':app.overlapIndicatorComponent,},props:['dish','allModifiers','recalc','callWaiter','submitText','hideCounter'],provide:function(){var mods=this.allModifiers||[];var sizes=mods[0]||{options:[{pos:0,price:0}],selected:0};if(sizes.selected===undefined){sizes.selected=0}
807var regular=[];for(var i=1;i<mods.length;i++){if(mods[i].type!=='combo'){regular.push(mods[i])}}
808var company=this.$store.state.company;var store={isAppearanceTiles:company&&company.toppingAppearance==='tiles',isAppearanceInput:company&&company.toppingCounterAppearance==='input',dish:this.dish};var loc=this.$store.state.loc;this._tpSizes=sizes;this._tpRegularModifiers=regular;this._tpStore=store;this._tpLoc=loc;return{store:store,loc:loc}},data:function(){return{isOverlap:!1}},computed:Object.assign({isDesktopVersion:function(){return this.isKiosk||!this.mobile},sizes:function(){return this._tpSizes},regularModifiers:function(){return this._tpRegularModifiers||[]},tpStore:function(){return this._tpStore},tpLoc:function(){return this._tpLoc},pointsCart:function(){return app.tpSizesAvailability.hasPointsMinSum(!1,this.dish)?this.cart:null}},Vuex.mapState(['mobile','isKiosk','company','cart','userHasToSubscribe'])),methods:{isAddressOk:function(){return!0},onSubmit:function(selected){this.recalc(selected.dishPos,selected.count,selected.addWeight)},onAlert:function(e){app.tpSiteAlert(e)}},store:app.store,template:`
809    <div class="tp">
810
811        <template v-if="isDesktopVersion">
812            <tp-image class="tp__image"/>
813        </template>
814
815        <div class="tp__data">
816
817            <!-- Четвертинок у части комбо нет -->
818            <tp-info :isApp="false"
819                     :isDesktopVersion="isDesktopVersion"
820                     :dish="dish"
821                     :sizes="sizes"
822                     :isQuarterActive="false"
823                     :loc="tpLoc"
824                     :company="company"/>
825
826            <div class="tp__content">
827
828                <tp-sizes :isApp="false"
829                          :isDesktopVersion="isDesktopVersion"
830                          :dish="dish"
831                          :sizes="sizes"
832                          :loc="tpLoc"
833                          :company="company"/>
834
835                <slot name="content">
836                    <tp-params :isApp="false"
837                               :dish="dish"
838                               :sizes="sizes"/>
839
840                    <slot name="beforeModifiers"></slot>
841
842                    <tp-modifier
843                        v-for="modifier in regularModifiers"
844                        :key="modifier.id || modifier.pos"
845                        :isApp="false"
846                        :modifier="modifier"
847                        :sizes="sizes"
848                        :loc="tpLoc"
849                        :isAppearanceTiles="tpStore.isAppearanceTiles"/>
850
851                    <slot name="afterModifiers"></slot>
852
853                    <overlap-indicator
854                        v-if="isDesktopVersion"
855                        v-model="isOverlap"/>
856                </slot>
857
858            </div>
859
860        </div>
861
862        <slot name="submit">
863            <tp-submit
864                :isApp="false"
865                :dish="dish"
866                :sizes="sizes"
867                :modifiers="regularModifiers"
868                :loc="tpLoc"
869                :company="company"
870                :cart="pointsCart"
871                :isAppearanceInput="tpStore.isAppearanceInput"
872                :isAddressOk="isAddressOk"
873                :userHasToSubscribe="userHasToSubscribe"
874                :shadow="isOverlap"
875                :hideCount="hideCounter"
876                :submitText="submitText"
877                @submit="onSubmit"
878                @callWaiter="callWaiter()"
879                @alert="onAlert"/>
880        </slot>
881
882    </div>
883    `};

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