1let webLatestVersion = 10; //Update this every time a new version is added. This should correspond to the version of the snake clone in v/current. 2 3//Code in here runs before snake-mod-loader-web.js 4//Useful to help set stuff up specific to the web version, that doesn't belong in the mod-loader script 5 6window.webSnake = window.webSnake ?? {}; 7window.webSnake.logUrlChanges = false; 8 9//Disable analytics 10window.navigator.sendBeacon = function() { 11 //Do nothing 12 window.webSnake.logUrlChanges && console.log('beacon disabled'); 13} 14 15//Disable google logging 16window.google.log = function() { 17 //Do nothing 18 window.webSnake.logUrlChanges && console.log('google.log disabled'); 19} 20 21window.google.logUrl = function() { 22 //Do nothing 23 window.webSnake.logUrlChanges && console.log('google.logUrl disabled'); 24} 25 26//Update url redirects to be relative 27//Commented out as this might not be needed 28/* 29window.webSnake.urlMap.forEach(rule => { 30 const thisUrl = new URL(document.location); 31 const urlStart = thisUrl.origin + thisUrl.pathname; 32 rule.newUrl = thisUrl.origin + thisUrl.pathname + rule.newUrl; 33}); 34*/ 35 36//Block urls in xhr 37window.oldXhrOpen = XMLHttpRequest.prototype.open; 38XMLHttpRequest.prototype.open = function () { 39 let url = makeUrlAbsolute(arguments[1]); 40 41 if(window.webSnake.blockedUrls.includes(url)) { 42 window.webSnake.logUrlChanges && console.log('Blocking url: ' + url); 43 throw new Error('Blocking url ' + url); //Slightly sketchy to error here as it may have side effects. This seems ok in practise 44 } 45 46 return oldXhrOpen.apply(this, arguments); 47}; 48 49window.oldFetch = window.fetch; 50 51window.fetch = function(url) { 52 if(typeof url === 'string') { 53 let mapping = window.webSnake.urlMap.find(m=>m.oldUrl === url); 54 55 if(mapping && mapping.newUrl) { 56 window.webSnake.logUrlChanges && console.log('Redirecting url: ' + url); 57 arguments[0] = mapping.newUrl; 58 } 59 } 60 61 return window.oldFetch(...arguments); 62} 63 64function makeUrlAbsolute(url) { 65 //If url starts with / then add https://www.google.com 66 if (/^\/[^\/]/.test(url)) { 67 url = "https://www.google.com" + url; 68 } 69 return url; 70} 71 72function switchToMobile() { 73 const currentGameVersion = getGameVersionFromUrl(); //defined in snake-mod-loader-web.js 74 75 //Add is-mobile data attribute 76 let snakeContainer = document.getElementsByClassName('EjCLSb')[0]; 77 snakeContainer.dataset.isMobile = ''; 78 79 //Delete fullscreen button 80 let fullscreenButtonOld = document.querySelector('img[src$="fullscreen_white_24dp.png"]') 81 if(fullscreenButtonOld) { 82 fullscreenButtonOld.remove(); 83 } 84 85 let fullscreenButtonsNew = document.querySelectorAll('div.EFcTud[jsaction="zeJAAd"]'); 86 if(fullscreenButtonsNew.length > 0) { 87 [...fullscreenButtonsNew].forEach(button => button.remove()); 88 } 89 90 //Add styles needed for mobile 91 let css = ` 92 93 /*Flexible size for snake container*/ 94 .EjCLSb { 95 height: 100% !important; 96 min-height: 0 !important; 97 min-width: 0 !important; 98 width: 100% !important; 99 } 100 101 /*Don't centre the snake container*/ 102 .yZz3de { 103 position: static !important; 104 left: 0 !important; 105 top: 0 !important; 106 transform: none !important; 107 } 108 109 /*Change keys image to swipe image*/ 110 .rNjvu { 111 background-image: url(//www.google.com/logos/fnbx/snake_arcade/swipe.svg) !important 112 } 113 114 /*Menu modal panels don't overlap edge*/ 115 .T7SB3d { 116 width: calc(100% - 64px) !important; 117 max-width: 300px !important; 118 } 119 120 /*Buttons below menu modal dont overlap edge*/ 121 .wUt0xf { 122 width: calc(100% - 64px) !important; 123 max-width: 300px !important; 124 } 125 126 /*Current/highscore on menu modal taking up less space*/ 127 @media only screen and (max-width: 315px),only screen and (orientation:landscape) and (max-height:315px) { 128 .bF4Gmf { 129 margin-left:5% !important; 130 margin-right: 5% !important; 131 } 132 } 133 134 /*Current/highscore on menu modal taking up less space*/ 135 @media only screen and (max-width: 215px),only screen and (orientation:landscape) and (max-height:215px) { 136 .bF4Gmf { 137 margin-left:0% !important; 138 margin-right: 0% !important; 139 } 140 } 141 142 /*score on top bar less wide*/ 143 .HIonyd { 144 width: 45px !important; 145 } 146 147 /*score on top bar less wide responsively*/ 148 @media only screen and (max-width: 285px), only screen and (orientation: landscape) and (max-height: 285px) 149 .HIonyd { 150 width: 35px !important; 151 padding-left: 0 !important; 152 } 153 `; 154 155 if(currentGameVersion >= 5) { 156 //Add in additional changes to the html/css that were introduced in version 5 157 css += ` 158 /*hide icons on the menu buttons (play/settings/daily challenge) to save space on small screens*/ 159 @media only screen and (max-width: 285px) { 160 .DwxlBd { 161 display:none 162 } 163 } 164 165 /* I'm not 100% sure what .jKj29e is for. 166 I suspect it is used to hide menu buttons as above when the translations for play/settings/daily challenge are really long (>20 chars) 167 */ 168 @media only screen and (max-width: 340px) { 169 .jKj29e .DwxlBd { 170 display:none 171 } 172 173 .jKj29e .qM98Ge { 174 visibility: hidden 175 } 176 } 177 178 /* Same as above, but .KjMIn is for translations >25 chars. 179 @media only screen and (max-width: 355px) { 180 .jKj29e .DwxlBd { 181 display:none 182 } 183 184 .KjMIn .qM98Ge { 185 visibility: hidden 186 } 187 } 188 189 /* .SU4xse is set when the daily challenge menu is visible */ 190 @media only screen and (max-width: 340px) { 191 /* Smaller image icons */ 192 .SU4xse .fbftZe { 193 width:28px 194 } 195 196 /* Probably image icons again on daily challenge if there are at least 5 modes? */
197 .SU4xse .OZ9aHc { 198 border-radius: 4px; 199 margin: 3px; 200 padding: 3px; 201 width: 20px 202 } 203 204 /* Small daily challenge icons in the "previous days" view */ 205 .SU4xse .Cg6pxb .fbftZe { 206 border-radius: 4px; 207 margin: 8px 2px; 208 padding: 2px; 209 width: 16px 210 } 211 } 212 213 /* Various restrictions based on height */ 214 @media only screen and (max-height: 650px) { 215 /* Shorter play/settings/daily challenge buttons */ 216 .FL0z2d { 217 height:36px; 218 margin-top: 8px 219 } 220 221 /* Shorter play/settings/daily challenge icons */ 222 .DwxlBd { 223 height: 30px; 224 width: 30px 225 } 226 227 /* Small play/settings/daily challenge font-size */ 228 .l3ryBd { 229 font-size: 17px 230 } 231 232 /* Maybe something for svgs? No idea really */ 233 .w9ahb { 234 height: 26px; 235 width: 26px 236 } 237 238 .w9ahb svg { 239 width: 100%; 240 height: 100% 241 } 242 } 243 244 /* Undo some styles that exist only of the desktop version */ 245 /* remove aspect ratio constraint on game canvas */ 246 .jNB0Ic { 247 aspect-ratio: auto !important; 248 } 249 250 /*main container of everything */ 251 :not(.DgO4x).EjCLSb { 252 max-width: none !important; 253 } 254 255 /*main container of everything */ 256 @media only screen and (min-height: 650px) { 257 :not(.DgO4x).EjCLSb { 258 max-height: none !important; 259 } 260 } 261 262 /* Custom css for gsm so that the button for enabling touch pad controls isn't blocked */ 263 .O6HIqc { 264 right: unset !important; 265 left: 10px; 266 } 267 `; 268 269 //Add class so that game can adapt height depending on whether mobile touchpad is enabled 270 let divWithMainCanvas = document.getElementsByClassName('cer0Bd')[0].parentElement; 271 divWithMainCanvas.classList.add('azpHl'); 272 273 //Add stuff for the mobile touchpad (touchpad itself + the button to enable it) 274 let settingsOverlay = document.getElementsByClassName('wjOYOd')[0]; 275 276 const touchpadHtml = ` 277 <div jsname="Ycs2rd" class="Oiw5Ib" jsaction="touchstart:G0IZGc;touchmove:G0IZGc;touchend:G0IZGc" data-ved="0ahUKEwjzppHUw_eFAxWPR_EDHQIwB6kQvNgMCAM"> 278 <div class="KM6Me"> 279 <div jsname="MUDVS" class="CyfBUb fzrkB"> 280 <div class="YD2pbc"> 281 <svg height="100%" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> 282 <path d="M480-360 280-560h400L480-360Z" fill="#000000"></path> 283 </svg> 284 </div> 285 </div> 286 <div jsname="rmiREc" class="CyfBUb DVNA1b"> 287 <div class="YD2pbc"> 288 <svg height="100%" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> 289 <path d="M480-360 280-560h400L480-360Z" fill="#000000"></path> 290 </svg> 291 </div> 292 </div> 293 <div jsname="p4rndc" class="CyfBUb aq6vAe"> 294 <div class="YD2pbc"> 295 <svg height="100%" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> 296 <path d="M480-360 280-560h400L480-360Z" fill="#000000"></path> 297 </svg> 298 </div> 299 </div> 300 <div jsname="dICtMc" class="CyfBUb EyxhB"> 301 <div class="YD2pbc"> 302 <svg height="100%" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> 303 <path d="M480-360 280-560h400L480-360Z" fill="#000000"></path> 304 </svg> 305 </div> 306 </div> 307 </div> 308 <div jsname="k8ZH5e" class="ekPAb"> 309 <div class="SjfyTc"></div> 310 </div> 311 </div> 312 `; 313 314 const enableTouchpadButton = ` 315 <div class="O6HIqc" aria-label="Toggle virtual controls" role="button" tabindex="0" jsaction="Uex1ad"> 316 <div class="qMDOx">
317 <svg height="100%" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> 318 <path d="m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z" fill="#FFFFFF"></path> 319 </svg> 320 </div> 321 <div jsname="ZxgYgc" class="DZekPe vCjPXe" data-ved="0ahUKEwjzppHUw_eFAxWPR_EDHQIwB6kQxvMMCAU"> 322 <svg height="100%" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> 323 <path d="M172.309-260.001q-30.308 0-51.308-21t-21-51.435v-295.128q0-30.435 21-51.435 21-21 51.308-21h615.382q30.308 0 51.308 21t21 51.435v295.128q0 30.435-21 51.435-21 21-51.308 21H172.309Zm0-59.999h615.382q4.616 0 8.463-3.846 3.846-3.847 3.846-8.463v-295.382q0-4.616-3.846-8.463-3.847-3.846-8.463-3.846H172.309q-4.616 0-8.463 3.846-3.846 3.847-3.846 8.463v295.382q0 4.616 3.846 8.463 3.847 3.846 8.463 3.846Zm117.692-50.001h59.998v-80h80v-59.998h-80v-80h-59.998v80h-80v59.998h80v80Zm289.954 0q20.814 0 35.429-14.57 14.615-14.57 14.615-35.384t-14.57-35.429q-14.57-14.615-35.384-14.615t-35.429 14.57q-14.615 14.57-14.615 35.384t14.57 35.429q14.57 14.615 35.384 14.615Zm120-120q20.814 0 35.429-14.57 14.615-14.57 14.615-35.384t-14.57-35.429q-14.57-14.615-35.384-14.615t-35.429 14.57q-14.615 14.57-14.615 35.384t14.57 35.429q14.57 14.615 35.384 14.615ZM160-320V-640-320Z" fill="#FFFFFF"></path> 324 </svg> 325 </div> 326 <div jsname="fIqioc" class="ufnB2c vCjPXe" data-ved="0ahUKEwjzppHUw_eFAxWPR_EDHQIwB6kQxfMMCAY"> 327 <svg height="100%" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> 328 <path d="M172.309-260.001q-30.308 0-51.308-21t-21-51.435v-295.128q0-30.435 21-51.435 21-21 51.308-21h615.382q30.308 0 51.308 21t21 51.435v295.128q0 30.435-21 51.435-21 21-51.308 21H172.309Zm0-59.999h615.382q4.616 0 8.463-3.846 3.846-3.847 3.846-8.463v-295.382q0-4.616-3.846-8.463-3.847-3.846-8.463-3.846H172.309q-4.616 0-8.463 3.846-3.846 3.847-3.846 8.463v295.382q0 4.616 3.846 8.463 3.847 3.846 8.463 3.846Zm117.692-50.001h59.998v-80h80v-59.998h-80v-80h-59.998v80h-80v59.998h80v80Zm289.954 0q20.814 0 35.429-14.57 14.615-14.57 14.615-35.384t-14.57-35.429q-14.57-14.615-35.384-14.615t-35.429 14.57q-14.615 14.57-14.615 35.384t14.57 35.429q14.57 14.615 35.384 14.615Zm120-120q20.814 0 35.429-14.57 14.615-14.57 14.615-35.384t-14.57-35.429q-14.57-14.615-35.384-14.615t-35.429 14.57q-14.615 14.57-14.615 35.384t14.57 35.429q14.57 14.615 35.384 14.615ZM160-320V-640-320Z" fill="#FFFFFF"></path> 329 </svg> 330 </div> 331 </div> 332 `; 333 334 settingsOverlay.insertAdjacentHTML('beforebegin', touchpadHtml); 335 settingsOverlay.insertAdjacentHTML('afterbegin', enableTouchpadButton); 336 337 //Rotate game to portrait for mobile 338 const rotateGameMobileHtml = ` 339 <div jsname="ar2wLb" class="t6jjTb"> 340 <img class="xAAoNb" src="https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/screen_rotation/default/48px.svg" alt="Rotate device to portrait"> 341 </div> 342 `; 343 344 snakeContainer.insertAdjacentHTML('beforeend', rotateGameMobileHtml); 345 } 346 347 let styleElement = document.createElement('style'); 348 styleElement.innerHTML = css; 349 document.head.appendChild(styleElement); 350}
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.