1function injectRCEnv() { 2 const recurrentInjectEnv = window.__recurrent_inject_env; 3 4 if (recurrentInjectEnv) { 5 recurrentInjectEnv(rcmail.env); 6 } else { 7 console.error('RAIM inject env function not found.'); 8 } 9} 10 11function mountComponent(componentName) { 12 const componentId = 'raim_' + componentName + '_component'; 13 14 if (!document.getElementById(componentId)) { 15 console.error('Element with ID ' + componentId + ' not found.'); 16 return; 17 } 18 19 // Mount React app 20 if (window['__recurrent_' + componentName + '_mount']) { 21 window['__recurrent_' + componentName + '_mount'](componentId); 22 } else { 23 console.error('RAIM mount function __recurrent_' + componentName + '_mount not found.'); 24 } 25} 26 27// Memoizes the one-time load of the RAIM SPA bundle so that multiple components on 28// the same page share a single <script>/<link> injection instead of re-executing 29// main.js (and re-requesting the API config) once per component. 30var raimBundlePromise = null; 31 32function loadRAIMBundle() { 33 if (raimBundlePromise) { 34 return raimBundlePromise; 35 } 36 37 const assetsPath = 'static.php/plugins/recurrent/vendor/spa'; 38 39 raimBundlePromise = fetch(assetsPath + '/asset-manifest.json') 40 .then(response => response.json()) 41 .then(manifest => new Promise(function(resolve, reject) { 42 const scriptPath = manifest['files']['main.js']; 43 const stylePath = manifest['files']['main.css']; 44 45 var style = document.createElement('link'); 46 style.rel = 'stylesheet'; 47 style.type = 'text/css'; 48 style.href = assetsPath + '/' + stylePath; 49 document.head.appendChild(style); 50 51 var script = document.createElement('script'); 52 script.onload = function() { 53 injectRCEnv(); 54 rcmail.http_request('plugin.request_api_config'); 55 resolve(); 56 }; 57 script.onerror = function() { 58 reject(new Error('Failed to load RAIM bundle: ' + scriptPath)); 59 }; 60 script.src = assetsPath + '/' + scriptPath; 61 document.head.appendChild(script); 62 })); 63 64 return raimBundlePromise; 65} 66 67// Surface a user-visible error via Roundcube's native notification when the SPA 68// bundle cannot be loaded, so the user isn't left looking at a blank area. 69function showRAIMLoadError() { 70 let message = rcmail.gettext('loaderror', 'recurrent'); 71 if (!message || message === 'loaderror') { 72 message = 'Could not load this section. Please try again later.'; 73 } 74 75 rcmail.display_message(message, 'error'); 76} 77 78function loadRAIMAssets(componentName) { 79 loadRAIMBundle() 80 .then(function() { 81 mountComponent(componentName); 82 83 // Also mount popup if account component is needed 84 if (componentName === 'account') { 85 mountComponent('popup'); 86 } 87 }) 88 .catch(function(error) { 89 console.error('Error loading RAIM assets:', error); 90 91 // The popup is a non-essential overlay, so a load failure there stays 92 // silent; for the settings components, surface a notification. 93 if (componentName !== 'popup') { 94 showRAIMLoadError(); 95 } 96 }); 97}
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.