1app.scrollOverlapComponent={props:{value:{type:Object,default:function(){return{top:!1,bottom:!1}}}},data:function(){return{state:{top:!1,bottom:!1}}},mounted:function(){var self=this;var root=this.$refs.container;var emit=function(){self.$emit('input',{top:self.state.top,bottom:self.state.bottom})};this._topObserver=new IntersectionObserver(function(entries){self.state.top=entries[0].intersectionRatio<1;emit()},{root:root,threshold:1});this._bottomObserver=new IntersectionObserver(function(entries){self.state.bottom=entries[0].intersectionRatio<1;emit()},{root:root,threshold:1});this._topObserver.observe(this.$refs.top);this._bottomObserver.observe(this.$refs.bottom)},beforeDestroy:function(){if(this._topObserver)this._topObserver.disconnect();if(this._bottomObserver)this._bottomObserver.disconnect();},template:` 2 <div ref="container" class="scrollOverlap"> 3 <div ref="top" class="scrollOverlap__edge scrollOverlap__edge--top"></div> 4 <slot></slot> 5 <div ref="bottom" class="scrollOverlap__edge scrollOverlap__edge--bottom"></div> 6 </div> 7 `};app.comboPartComponent={props:['section','selected'],computed:Object.assign({selectedDish:function(){if(!this.selected){return null} 8var options=this.section.options||[];for(var i=0;i<options.length;i++){if(options[i].id===this.selected.dishId){return options[i]}} 9return null},image:function(){var dish=this.selectedDish||(this.section.options&&this.section.options[0]);if(!dish){return null} 10var img=dish.image||(dish.media&&dish.media[0]);if(!img){return null} 11return img.preview||img.full||img.low||null},title:function(){if(this.selected){return this.selected.dishName} 12var match=this.section.title.match(/(.*)\s*\(.*\)/);return match?match[1].trim():this.section.title},sub:function(){if(this.selectedDish){return this.selectedDish.ingredients||null} 13var match=this.section.title.match(/\((.*)\)/);return match?match[1]:null},dishesCount:function(){return(this.section.options||[]).length},actionText:function(){return this.selected?(this.loc['btn/replace']||'Replace'):(this.loc['btn/choose']||'Choose')}},Vuex.mapState(['loc'])),template:` 14 <div class="comboPart" @click="$emit('open')"> 15 16 <div class="comboPart__media"> 17 <img v-if="image" :src="image" class="comboPart__img" alt=""> 18 <div v-else class="comboPart__stub"> 19 <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="1.5"> 20 <rect x="3" y="3" width="18" height="18" rx="2"/> 21 <circle cx="8.5" cy="8.5" r="1.5"/> 22 <path d="M21 15l-5-5L5 21"/> 23 </svg> 24 </div> 25 </div> 26 27 <div class="comboPart__body"> 28 <div class="comboPart__info"> 29 <div class="comboPart__title">{{ title }}</div> 30 <div v-if="sub" class="comboPart__sub">{{ sub }}</div> 31 </div> 32 33 <div class="comboPart__action" :class="{'comboPart__action--selected': selected}"> 34 {{ actionText }} 35 <span class="comboPart__count">· {{ dishesCount }}</span> 36 <svg class="comboPart__arrow" width="7" height="11" viewB
36ox="0 0 7 11" fill="none"> 37 <path d="M1 10L5.5 5.5L1 1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 38 </svg> 39 </div> 40 </div> 41 42 <transition name="comboPartCheck"> 43 <svg v-if="selected" class="comboPart__check" width="20" height="20" viewBox="0 0 20 20" fill="none"> 44 <circle cx="10" cy="10" r="10" fill="#34C759"/> 45 <path d="M6 10.5L8.5 13L14 7" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 46 </svg> 47 </transition> 48 49 </div> 50 `};app.comboAlternativesComponent={components:{'scroll-overlap':app.scrollOverlapComponent,},props:['section','currentDishId'],data:function(){return{overlap:{top:!1,bottom:!1}}},computed:Object.assign({dishes:function(){return this.section.options||[]}},Vuex.mapState(['loc'])),methods:{imgSrc:function(dish){var img=dish.image||(dish.media&&dish.media[0]);if(!img){return'/assets/company2/menu/i/bg.png'} 51return img.preview||img.full||img.low||'/assets/company2/menu/i/bg.png'},getModifiers:function(dish){var dishModifiers=dish.modifiers||[];var sectionModifiers=this.section.modifiers||[];if(dishModifiers.length<2){return dishModifiers.concat(sectionModifiers)} 52return dishModifiers},selectDish:function(dish){if(!dish.comboPos){this.$emit('topping',{dish:dish,modifiers:this.getModifiers(dish)});return} 53this.$emit('select',app.buildComboSelection(dish))},locButton:function(dish){if(this.currentDishId===dish.id){return this.loc['btn/selected']||'Selected'} 54return this.loc['btn/choose']||'Choose'},isActive:function(dish){return this.currentDishId===dish.id}},template:` 55 <div class="comboSection" 56 :class="{ 57 'comboSection--overlapTop': overlap.top, 58 'comboSection--overlapBottom': overlap.bottom 59 }"> 60 <scroll-overlap v-model="overlap" class="comboSection__scroll"> 61 <div class="comboSection__grid"> 62 <div v-for="dish in dishes" 63 :key="dish.id" 64 class="comboSection__dish" 65 :class="{'comboSection__dish--active': isActive(dish)}" 66 @click="selectDish(dish)"> 67 68 <div class="comboSection__image"> 69 <img :src="imgSrc(dish)" 70 alt="" 71 loading="lazy" 72 class="comboSection__img"> 73 </div> 74 75 <div class="comboSection__info"> 76 <div> 77 <div class="comboSection__name">{{ dish.name }}</div> 78 <div v-if="dish.ingredients" class="comboSection__ingredients">{{ dish.ingredients }}</div> 79 </div> 80 81 <button class="comboSection__btn" 82 :class="{'comboSection__btn--active': isActive(dish)}" 83 @click.stop="selectDish(dish)"> 84 <svg v-if="isActive(dish)" class="comboSection__btnCheck" width="13" height="11" viewB
84ox="0 0 13 11" fill="none"> 85 <path d="M1 5.5L4.5 9L12 1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 86 </svg> 87 {{ locButton(dish) }} 88 </button> 89 </div> 90 91 </div> 92 </div> 93 </scroll-overlap> 94 </div> 95 `};app.comboViewPartsComponent={components:{'tp-shell':app.tpShellComponent,'combo-part':app.comboPartComponent,},props:['dish','comboSections','comboSelected','modifiers','comboTotalFormatted','allComboPicked'],computed:Vuex.mapState(['loc']),template:` 96 <div class="combo__view"> 97 <tp-shell :dish="dish" :allModifiers="modifiers" :recalc="function(){}" :callWaiter="function(){}"> 98 <template #content> 99 <div class="combo__sections"> 100 <combo-part 101 v-for="(section, idx) in comboSections" 102 :key="section.id" 103 :section="section" 104 :selected="comboSelected[idx]" 105 @open="$emit('open-section', idx)"/> 106 </div> 107 </template> 108 <template #submit> 109 <div class="tsubmit"> 110 <div class="tsubmit__buttons"> 111 <div class="tsubmit__button" :class="{'tsubmit__button--disabled': !allComboPicked}" @click="$emit('submit')"> 112 <div class="tsubmit__text">{{ loc['topping/add'] }}</div> 113 <svg class="tsubmit__delimiter" width="2" height="20" viewBox="0 0 2 20" fill="none" xmlns="http://www.w3.org/2000/svg"> 114 <line x1="0.865723" y1="0.590576" x2="0.865722" y2="18.5906" stroke="currentColor" stroke-linecap="round" stroke-dasharray="1 4"/> 115 </svg> 116 <div class="tsubmit__total">{{ comboTotalFormatted }}</div> 117 </div> 118 </div> 119 </div> 120 </template> 121 </tp-shell> 122 </div> 123 `};app.buildComboSelection=function(dish){return{dishId:dish.id,dishPos:dish.comboPos,dishName:dish.name,dishTotal:dish.priceRaw||0,}};var findPreselectedOption=function(section){if(!section.preselectedDishId){return null} 124var options=section.options||[];for(var i=0;i<options.length;i++){if(options[i].id===section.preselectedDishId&&options[i].comboPos){return options[i]}} 125return null};var buildState=function(params){var modifiers=params.modifiers||[];var sizes=modifiers[0]||{options:[],selected:0};if(sizes.selected===undefined){sizes.selected=0} 126var comboSections=[];for(var i=1;i<modifiers.length;i++){if(modifiers[i].type==='combo'){comboSections.push(modifiers[i])}} 127var comboSelected=new Array(comboSections.length).fill(null);for(var p=0;p<comboSections.length;p++){var option=findPreselectedOption(comboSections[p]);if(option){comboSelected[p]=app.buildComboSelection(option)}} 128var preselected=params.dish.combo&¶ms.dish.combo.selected;if(preselected){for(var s=0;s<preselected.length&&s<comboSections.length;s++){if(preselected[s]){comboSelected[s]=preselected[s]}}} 129return{dish:params.dish,modifiers:modifiers,sizes:sizes,comboSections:comboSections,comboSelected:comboSelected,comboView:'parts',comboSectionIdx:null,comboSubDish:null,forceAddress:params.forceAddress,forceRemoveDish:params.forceRemoveDish,subDishKey:0,}};var buildSubSelection=function(comboSubDish,dishPosId){var mods=comboSubDish.modifiers||[];var subSizes=mods[0]||{options:[{pos:0,price:0}],selected:0};var sizeKey=subSizes.selected||0;var sizeOption=subSizes.options&&subSizes.options[sizeKey];var dishTotal=sizeOption?(sizeOption.price||0):0;var modifierNames=[];for(var m=1;m<mods.length;m++){var options=mods[m].options||[];for(var n=0;n<options.length;n++){var opt=options[n];if(opt.count&&typeof opt.price==='number'){dishTotal+=opt.price*opt.count} 130if(opt.count&&opt.name){modifierNames.push(opt.count>1?opt.name+' Ã'+opt.count:opt.name)}}} 131var fullName=comboSubDish.dish.name;if(modifierNames.length){fullName+=' + '+modifierNames.join(', ')} 132return{dishId:comboSubDish.dish.id,dishPos:dishPosId,dishName:fullName,dis
132hTotal:dishTotal,}};app.buildComboOrchestratorComponent=function(params){return{components:{'combo-view-parts':app.comboViewPartsComponent,'combo-alternatives':app.comboAlternativesComponent,'tp-shell':app.tpShellComponent,},provide:function(){var mods=params.modifiers||[];var sizes=mods[0]||{options:[{pos:0,price:0}],selected:0};if(sizes.selected===undefined){sizes.selected=0} 133return{store:{isAppearanceTiles:!1,isAppearanceInput:!1,dish:params.dish,sectionId:0,modifiers:mods,forceAddress:params.forceAddress,forceRemoveDish:params.forceRemoveDish},sizes:sizes,modifiers:[],ingredients2:params.dish.ingredients2,nutrients:params.dish.nutrients,loc:this.$store.state.loc,isQuarterActive:!1}},data:function(){return buildState(params)},computed:Object.assign({allComboPicked:function(){for(var i=0;i<this.comboSections.length;i++){if(!this.comboSelected[i]){return!1}} 134return!0},comboTotalFormatted:function(){var sizeKey=this.sizes.selected||0;var sizeOption=this.sizes.options&&this.sizes.options[sizeKey];var basePrice=sizeOption?(sizeOption.price||0):0;var partsPrice=0;for(var j=0;j<this.comboSelected.length;j++){if(this.comboSelected[j]){partsPrice+=this.comboSelected[j].dishTotal||0}} 135var currency=this.company?this.company.currency:'';var separator=this.company?this.company.priceSeparator:'';return app.price.format(basePrice+partsPrice,currency,separator)},sectionTitle:function(){if(this.comboView==='section'&&this.comboSectionIdx!==null){var section=this.comboSections[this.comboSectionIdx];if(section){var match=section.title.match(/(.*)\s*\(.*\)/);return match?match[1].trim():section.title}} 136if(this.comboView==='subTopping'&&this.comboSubDish){return this.comboSubDish.dish.name} 137return''},isDesktopVersion:function(){return this.isKiosk||!this.mobile}},Vuex.mapState(['loc','mobile','isKiosk','company'])),methods:{openSection:function(idx){this.comboSectionIdx=idx;this.comboView='section'},backToParts:function(){this.comboView='parts';this.comboSectionIdx=null;this.comboSubDish=null},onComboSelect:function(idx,selection){this.$set(this.comboSelected,idx,selection);this.backToParts()},onComboTopping:function(idx,payload){var data=JSON.parse(JSON.stringify(payload));data._sectionIdx=idx;this.comboSubDish=data;this.subDishKey++;this.comboView='subTopping'},backToSection:function(){var idx=this.comboSubDish?this.comboSubDish._sectionIdx:null;this.comboSubDish=null;this.comboView='section';if(idx!==null){this.comboSectionIdx=idx}},subToppingRecalc:function(dishPosId){var idx=this.comboSubDish?this.comboSubDish._sectionIdx:null;if(idx!==null){this.$set(this.comboSelected,idx,buildSubSelection(this.comboSubDish,dishPosId))} 138this.backToParts()},comboSubmit:function(){if(!this.allComboPicked){var missing='';for(var i=0;i<this.comboSections.length;i++){if(!this.comboSelected[i]){missing=this.comboSections[i].title.split(' (')[0];break}} 139app.alert((this.loc['topping/warning/comboNotFilled']||'Please select: {section}').replace('{section}',missing),'danger');return} 140if(this.forceAddress){PubSub.publish(this.forceAddress,{forceReload:!0,openDishAfterReload:{id:this.dish.id,name:this.dish.name}});return} 141var sizeKey=this.sizes.selected||0;var comboParts=[];for(var j=0;j<this.comboSelected.length;j++){if(this.comboSelected[j]){comboParts.push(this.comboSelected[j].dishPos)}} 142var dishPosId=this.dish.id+'_'+sizeKey+'#'+comboParts.join('#');PubSub.publish('dishSelected',{dishPosId:dishPosId,count:1,forceRemoveDish:this.forceRemoveDish,});this.$emit('close')},callWaiter:function(){var self=this;setTimeout(function(){PubSub.publish('showWaiter',{action:'call-waiter'})},600);self.$emit('close')}},store:app.store,template:` 143 <div class="combo"> 144 <svg xmlns="http://www.w3.org/2000/svg" style="display: none"> 145 <symbol id="icon__arrow" viewBox="0 0 9 15" xmlns="http://www.w3.org/2000/svg"> 146 <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"/> 147 </symbol> 148 <symbol id="tp__pointIcon" width="16" height="14" viewBox="0 0 16 14" fill="none"> 149 <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"/> 150 <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"/> 151 </symbol> 152 </svg> 153 <combo-view-parts 154 v-if="comboView === 'parts'" 155 :dish="dish" :comboSections="comboSections" :comboSelected="comboSelected" 156 :modifiers="modifiers" 157 :comboTotalFormatted="comboTotalFormatted" :allComboPicked="allComboPicked" 158 @open-section="openSection" @submit="comboSubmit"/> 159 <div v-else-if="comboView === 'section'" class="combo__view combo__view--section"> 160 <div class="combo__nav"> 161 <button class="combo__back" @click="backToParts"> 162 <svg width="9" height="15" viewBox="0 0 9 15" fill="none"> 163 <path d="M7.855 14.509L9 13.349L2.906 7.254L9 1.16L7.855 0L0.6 7.255L7.855 14.509Z" fill="currentColor"/> 164 </svg> 165 </button> 166 <div class="combo__navTitle">{{ sectionTitle }}</div> 167 </div> 168 <div class="combo__sectionContent"> 169 <combo-alternatives 170 v-if="comboSections[comboSectionIdx]" 171 :section="comboSections[comboSectionIdx]" 172 :currentDishId="comboSelected[comboSectionIdx] ? comboSelected[comboSectionIdx].dishId : null" 173 @select="onComboSelect(comboSectionIdx, $event)" 174 @topping="onComboTopping(comboSectionIdx, $event)"/> 175 </div> 176 </div> 177 <div v-else-if="comboView === 'subTopping'" class="combo__view combo__view--subTopping"> 178 <button class="combo__backOverlay" @click="backToSection"> 179 <svg width="9" height="15" viewBox="0 0 9 15" fill="none"> 180 <path d="M7.855 14.509L9 13.349L2.906 7.254L9 1.16L7.855 0L0.6 7.255L7.855 14.509Z" fill="currentColor"/> 181 </svg> 182 </button> 183 <tp-shell 184 :key="subDishKey"
185 :dish="comboSubDish.dish" 186 :allModifiers="comboSubDish.modifiers" 187 :recalc="subToppingRecalc" 188 :callWaiter="callWaiter" 189 :submitText="loc['btn/choose']" 190 :hideCounter="true"/> 191 </div> 192 </div> 193 `}};app.addModule(function(){var show=function(vrParams){var runVm=function(params){app.openViewer({desktop:{maxWidth:'1050px',disableAutogrow:!0,overflow:'hidden'},mobile:{withTick:!0,withClose:!1,minHeight:'90dvh',maxHeight:'90dvh',backgroundColor:'transparent',},className:'tp__viewer',component:app.buildComboOrchestratorComponent(params),})};if(vrParams.preload){app.fetch('/cart/topping/get',vrParams.preload,function(response){if(response.error){return} 194response.dish.combo={active:!0};runVm(response)})}else{runVm(vrParams)}};PubSub.subscribe('showCombo',function(e,params){show(params);if(params.dish){PubSub.publish('gtmNotify',{event:'view_item',item:params.dish})}})});
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.