1/******/ (function() { // webpackBootstrap 2/******/ var __webpack_modules__ = ({ 3 4/***/ 327: 5/***/ (function() { 6 7/* 8 * Opplasting fra legacy-flater (plupload i .vm-views, Froala i bloc-primer/bloc-controlpanel) 9 * mot Bloc.WebAPI `api/upload/*` bak JWT. Erstatter den anonyme Bloc.UploaderCore 10 * (uploader.bloc.net / upload.webfarm3.bloc.no), avviklet 2026-09. 11 * 12 * Kanonisk kilde: Bloc.no/Scripts/bloc-webapi-upload.js. Bundles (frontend-js, controlpanel-js) 13 * importerer denne fila som side-effect-modul; views uten bundle laster den statisk fra 14 * /old/Scripts/bloc-webapi-upload.js. Ren ES5 og kun jQuery, sÃ¥ den virker overalt. 15 * 16 * Token: `token` i localStorage (samme som bloc-primer's jQueryJWTHeader), ellers 17 * /next/jwt/token. plupload's BeforeUpload er synkron, derfor synkron XHR der. 18 */ 19(function (window, jQuery) { 20 'use strict'; 21 22 if (window.BlocWebApiUpload) { 23 return; 24 } 25 26 function webApiBase() { 27 return window.Site && window.Site.webApiEndpoint ? window.Site.webApiEndpoint : ''; 28 } 29 30 function readStoredToken() { 31 var jwt = null; 32 33 try { 34 jwt = window.localStorage.getItem('token'); 35 } catch (e) { 36 /* storage kan være blokkert */ 37 } 38 39 return jwt && jwt !== 'null' ? jwt : null; 40 } 41 42 function storeToken(jwt) { 43 try { 44 window.localStorage.setItem('token', jwt); 45 } catch (e) { 46 /* ignorer */ 47 } 48 } 49 50 function clearToken() { 51 try { 52 window.localStorage.removeItem('token'); 53 } catch (e) { 54 /* ignorer */ 55 } 56 } 57 58 function tokenSync(forceRefresh) { 59 var jwt = forceRefresh ? null : readStoredToken(); 60 61 if (jwt) { 62 return jwt; 63 } 64 65 jQuery.ajax({ 66 url: '/next/jwt/token', 67 async: false, 68 cache: false, 69 success: function (data) { 70 if (data && data !== 'null') { 71 jwt = data; 72 storeToken(data); 73 } 74 } 75 }); 76 return jwt; 77 } 78 79 function tokenAsync(forceRefresh, done) { 80 var jwt = forceRefresh ? null : readStoredToken(); 81 82 if (jwt) { 83 done(jwt); 84 return; 85 } 86 87 jQuery.ajax({ 88 url: '/next/jwt/token', 89 cache: false, 90 success: function (data) { 91 if (data && data !== 'null') { 92 storeToken(data); 93 done(data); 94 } else { 95 done(null); 96 } 97 }, 98 error: function () { 99 done(null); 100 } 101 }); 102 } 103 104 function errorMessage(xhr, fallback) { 105 var body = xhr && xhr.responseJSON; 106 return body && body.message || fallback; 107 } // ââ plupload (chunket) âââââââââââââââââââââââââââââââââââââââââââââââââââââ 108 // Bind i BeforeUpload: `return window.BlocWebApiUpload.pluploadBeforeUpload(up, file);` 109 // Setter url/headers/location pÃ¥ uploaderen; view-spesifikke multipart_params beholdes. 110 // Serveren leser `location`, `chunk`, `chunks` fra form-feltene plupload sender. 111 112 113 function pluploadBeforeUpload(up, file) { 114 var location = null; 115 var jwt = tokenSync(false); 116 var attempt = 0; 117 118 function init() { 119 attempt += 1; 120 jQuery.ajax({ 121 type: 'POST', 122 async: false, 123 url: webApiBase() + '/api/upload/BigFileInit', 124 contentType: 'application/json', 125 data: JSON.stringify({ 126 fileName: file.name, 127 totalBytes: file.size 128 }), 129 headers: { 130 Authorization: 'Bearer ' + jwt 131 }, 132 dataType: 'json', 133 success: function (data) { 134 if (data && data.success && data.location) { 135 location = data.location; 136 } else { 137 window.alert(data && data.message || 'Upload failed'); 138 } 139 }, 140 error: function (xhr) { 141 if (xhr.status === 401 && attempt === 1) { 142 clearToken(); 143 jwt = tokenSync(true); 144 145 if (jwt) { 146 init(); 147 } 148 149 return; 150 } 151 152 window.alert(errorMessage(xhr, 'Upload failed (' + xhr.status + ')')); 153 } 154 }); 155 } 156 157 if (!jwt) { 158 window.alert('You must be signed in to upload files.'); 159 return false;
160 } 161 162 init(); 163 164 if (!location) { 165 return false; 166 } 167 168 up.settings.url = webApiBase() + '/api/upload/BigFileChunk'; 169 up.settings.headers = { 170 Authorization: 'Bearer ' + jwt 171 }; 172 up.settings.multipart_params = jQuery.extend({}, up.settings.multipart_params, { 173 location: location 174 }); 175 return true; 176 } // FileUploaded: `var value = BlocWebApiUpload.pluploadResult(obj);` â { url, blobname, bytes } eller null. 177 178 179 function pluploadResult(obj) { 180 var value = null; 181 182 try { 183 value = jQuery.parseJSON(obj.response); 184 } catch (e) { 185 value = null; 186 } 187 188 if (!value || !value.success || !value.completed || !value.url) { 189 window.alert(value && value.message || 'Upload failed'); 190 return null; 191 } 192 193 return value; 194 } // ââ enkeltfil (Froala m.m.) ââââââââââââââââââââââââââââââââââââââââââââââââ 195 // `progress` (valgfri) fÃ¥r XHR upload-progress-events. 196 197 198 function uploadSingle(action, file, done, progress) { 199 var attempt = 0; 200 201 function send(jwt) { 202 attempt += 1; 203 var formData = new window.FormData(); // blocFileName er reservenavnet withFileName setter nÃ¥r File-konstruktøren mangler. 204 205 var sendAs = file.name || file.blocFileName; 206 207 if (sendAs) { 208 formData.append('file', file, sendAs); 209 } else { 210 formData.append('file', file); 211 } 212 213 jQuery.ajax({ 214 type: 'POST', 215 url: webApiBase() + '/api/upload/' + action, 216 data: formData, 217 cache: false, 218 contentType: false, 219 processData: false, 220 headers: { 221 Authorization: 'Bearer ' + jwt 222 }, 223 xhr: function () { 224 var xhr = jQuery.ajaxSettings.xhr(); 225 226 if (progress && xhr.upload) { 227 xhr.upload.addEventListener('progress', progress, false); 228 } 229 230 return xhr; 231 }, 232 success: function (data) { 233 if (data && data.success && data.url) { 234 done(null, data); 235 } else { 236 done(data && data.message || 'Upload failed', null); 237 } 238 }, 239 error: function (xhr) { 240 if (xhr.status === 401 && attempt === 1) { 241 clearToken(); 242 tokenAsync(true, function (fresh) { 243 if (fresh) { 244 send(fresh); 245 } else { 246 done('You must be signed in to upload files.', null); 247 } 248 }); 249 return; 250 } 251 252 done(errorMessage(xhr, 'Upload failed (' + xhr.status + ')'), null); 253 } 254 }); 255 } 256 257 tokenAsync(false, function (jwt) { 258 if (!jwt) { 259 done('You must be signed in to upload files.', null); 260 return; 261 } 262 263 send(jwt); 264 }); 265 } // Endelsene Bloc.WebAPI godtar for editor-bilder (Const.ImageUploadAllowList). 266 267 268 var EDITOR_IMAGE_EXT_BY_MIME = { 269 'image/jpeg': 'jpg', 270 'image/jpg': 'jpg', 271 'image/png': 'png', 272 'image/gif': 'gif', 273 'image/webp': 'webp', 274 'image/avif': 'avif' 275 }; 276 /* 277 * Froala bygger et navnløst Blob for LIMTE bilder (`_processPastedImage`) og setter filnavn 278 * først ETTER at image.beforeUpload har returnert true. Vi returnerer false og laster opp 279 * selv, sÃ¥ navnet ble aldri satt: FormData sendte filename="undefined", og 280 * api/upload/UploadImage avviste opplastingen pÃ¥ manglende filendelse. 281 * 282 * Bildet ble da liggende igjen som base64 i artikkelteksten, Blog_Post.Image ble tom 283 * (GetFirstImageInText matcher bare http(s)-URL-er) og nyhetswidgeten tegnet grÃ¥tt felt. 284 * Sak 1301/1315. Frontend-tvillingen i bloc-frontend fikk fiksen 11.09.2026 (e15e8599d); 285 * denne fila er den legacy-flatene bruker, og hadde den samme feilen uendret. 286 */ 287 288 function withFileName(image) { 289 if (image.name && /\.[a-z0-9]+$/i.test(image.name)) { 290 return image; 291 } 292 293 var ext = EDITOR_IMAGE_EXT_BY_MIME[String(image.type || '').toLowerCase()] || 'png'; 294 var name = Date.now() + '.' + ext; 295 296 try { 297 return new window.File([image], name, { 298 type: image.type 299 }); 300 } catch (e) { 301 // Eldre nettlesere uten File-konstruktør: la navnet følge med i FormData i stedet. 302 image.blocFileName = name; 303 return image; 304 } 305 } // Froala v3/v4 events (`this` = editor). Returnerer false sÃ¥ Froala ikke poster selv. 306 307 308 function froalaImageBeforeUpload(images) { 309 var editor = this; 310 var file = images && images[0]; 311 312 if (!file) { 313 return false;
314 } 315 316 file = withFileName(file); 317 var $existing = editor.image.get(); 318 uploadSingle('UploadImage', file, function (err, data) { 319 if (err) { 320 editor.popups.hideAll(); 321 window.alert(err); 322 return; 323 } 324 325 editor.image.insert(data.url + '?autorotate=true', false, null, $existing); 326 }); 327 return false; 328 } 329 330 function froalaFileBeforeUpload(files) { 331 var editor = this; 332 var file = files && files[0]; 333 334 if (!file) { 335 return false; 336 } 337 338 uploadSingle('UploadFile', file, function (err, data) { 339 if (err) { 340 editor.popups.hideAll(); 341 window.alert(err); 342 return; 343 } 344 345 editor.file.insert(data.url, data.filename || file.name); 346 }); 347 return false; 348 } 349 350 window.BlocWebApiUpload = { 351 tokenSync: tokenSync, 352 tokenAsync: tokenAsync, 353 pluploadBeforeUpload: pluploadBeforeUpload, 354 pluploadResult: pluploadResult, 355 uploadSingle: uploadSingle, 356 froalaImageBeforeUpload: froalaImageBeforeUpload, 357 froalaFileBeforeUpload: froalaFileBeforeUpload 358 }; 359})(window, window.jQuery); 360 361/***/ }) 362 363/******/ }); 364/************************************************************************/ 365/******/ // The module cache 366/******/ var __webpack_module_cache__ = {}; 367/******/ 368/******/ // The require function 369/******/ function __webpack_require__(moduleId) { 370/******/ // Check if module is in cache 371/******/ var cachedModule = __webpack_module_cache__[moduleId]; 372/******/ if (cachedModule !== undefined) { 373/******/ return cachedModule.exports; 374/******/ } 375/******/ // Create a new module (and put it into the cache) 376/******/ var module = __webpack_module_cache__[moduleId] = { 377/******/ // no module.id needed 378/******/ // no module.loaded needed 379/******/ exports: {} 380/******/ }; 381/******/ 382/******/ // Execute the module function 383/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); 384/******/ 385/******/ // Return the exports of the module 386/******/ return module.exports; 387/******/ } 388/******/ 389/************************************************************************/ 390/******/ /* webpack/runtime/compat get default export */ 391/******/ !function() { 392/******/ // getDefaultExport function for compatibility with non-harmony modules 393/******/ __webpack_require__.n = function(module) { 394/******/ var getter = module && module.__esModule ? 395/******/ function() { return module['default']; } : 396/******/ function() { return module; }; 397/******/ __webpack_require__.d(getter, { a: getter }); 398/******/ return getter; 399/******/ }; 400/******/ }(); 401/******/ 402/******/ /* webpack/runtime/define property getters */ 403/******/ !function() { 404/******/ // define getter functions for harmony exports 405/******/ __webpack_require__.d = function(exports, definition) { 406/******/ for(var key in definition) { 407/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 408/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 409/******/ } 410/******/ } 411/******/ }; 412/******/ }(); 413/******/ 414/******/ /* webpack/runtime/hasOwnProperty shorthand */ 415/******/ !function() { 416/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } 417/******/ }(); 418/******/ 419/************************************************************************/ 420var __webpack_exports__ = {}; 421// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 422!function() { 423// Replacing Modernizr with only what we need 424window.Modernizr = function () { 425 function _localStorage() { 426 var mod = 'modernizr'; 427 428 try { 429 localStorage.setItem(mod, mod); 430 localStorage.removeItem(mod); 431 return true; 432 } catch (e) { 433 return false; 434 } 435 } 436 437 function _history() { 438 var hasHistory = !!(window.history && history.pushState); 439 return hasHistory; 440 } 441 442 return { 443 hasLocalStorage: _localStorage(), 444 history: _history() 445 }; 446}(); 447}(); 448// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 449!function() { 450// Starting AppLaunch Namespace 451window.AppLaunch = { 452 loaderimage: "<i class=\"fa fa-circle-o-notch fa-spin\"></i>", 453 View: {}, 454 Widgets: {} 455}; 456 457const jQueryJWTHeader = () => { 458 var jwt = localStorage.getItem('token'); 459 460 if (jwt !== null) { 461 return jwt; 462 } 463 464 return jQuery.ajax({ 465 url: '/next/jwt/token', 466 timeout: 5000, 467 cache: false, 468 success: function (data, textStatus, jqXHR) { 469 if (data) {
470 localStorage.setItem('token', data ? data : 'null'); 471 } 472 473 return data; 474 }, 475 error: function (jqXHR, textStatus, errorThrown) { 476 return null; 477 } 478 }); 479}; 480 481const BlocJwtAjax = settings => { 482 jQuery.when(jQueryJWTHeader()).done(function (jwt) { 483 settings.headers = { 484 "Authorization": 'Bearer ' + jwt 485 }; 486 487 settings.error = function (xhr, status) { 488 if (xhr.status == 401) { 489 settings.error = null; 490 localStorage.removeItem('token'); 491 jQuery.when(window.jQueryJWTHeader()).done(function (jwtReTry) { 492 settings.headers = { 493 "Authorization": 'Bearer ' + jwtReTry 494 }; 495 jQuery.ajax(settings); 496 }); 497 } 498 }; 499 500 jQuery.ajax(settings); 501 }); 502}; 503 504window.jQueryJWTHeader = jQueryJWTHeader; 505window.BlocJwtAjax = BlocJwtAjax; 506 507const objectifyForm = formData => { 508 //serialize data function 509 let formArray = formData.serializeArray(); 510 var returnArray = {}; 511 512 for (var i = 0; i < formArray.length; i++) { 513 returnArray[formArray[i]['name']] = formArray[i]['value']; 514 } 515 516 return returnArray; 517}; 518 519window.objectifyForm = objectifyForm; // navigate to profile-card view 520 521const NavigateToNextProfileCard = vueRouterUrl => { 522 let currentUrl = window.location.pathname.toString(); //const slug = GetCurrentProfileCardSlug(); 523 //currentUrl = currentUrl.replace(slug, ''); 524 //// check if currentUrl contains vueRouterUrl, then handle it 525 526 const newUrl = currentUrl + vueRouterUrl; 527 window.VueRouter.push({ 528 path: newUrl 529 }); //window.history.pushState(null, null, new URL(newUrl)); 530}; 531 532window.NavigateToNextProfileCard = NavigateToNextProfileCard; 533 534const CloseNextProfileCard = () => { 535 const slug = GetCurrentProfileCardSlug(); 536 537 if (slug !== undefined && slug != '') { 538 const newUrl = window.location.toString().replace(slug, ''); 539 window.history.pushState(null, null, new URL(newUrl)); 540 } 541}; 542 543function GetCurrentProfileCardSlug() { 544 const currentUrl = window.location.toString(); 545 546 if (currentUrl.includes('/profile-card/') == true) { 547 const slug = '/profile-card' + currentUrl.split('profile-card').pop(); 548 return slug; 549 } 550 551 return ''; 552} 553 554window.CloseNextProfileCard = CloseNextProfileCard; 555}(); 556// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 557!function() { 558// Disable Multiple Submits 559// ======================== 560// Prevents forms from getting submitted multiple times 561// This method also works on enter and with jQuery Validate. 562$(document).on('submit submitHandler asyncSubmit', 'form', function () { 563 disableSubmitBtn(this); 564}); 565 566function disableSubmitBtn(form) { 567 var x = $(':submit', form); 568 var loader = $('<i class="fa fa-circle-o-notch fa-spin fn-loader-spinner-tag" style="margin-right: 5px;"></i>'); 569 570 if (!x.hasClass('keepEnabled')) { 571 x.attr('disabled', 'disabled'); 572 573 if (x.find('i.fn-loader-spinner-tag').length === 0) { 574 x.prepend(loader); 575 } 576 } 577 578 if (!x.hasClass('keepDisabled')) { 579 setTimeout(function () { 580 x.removeAttr('disabled'); 581 x.find('i.fn-loader-spinner-tag').remove(); 582 }, 2500); 583 } 584} 585 586window.disableSubmitBtn = disableSubmitBtn; 587}(); 588// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 589!function() { 590//#region Dropdown 591var topBarSubContentFocus = false; 592$(document).on('mouseenter mouseleave', '.sub-content', function () { 593 topBarSubContentFocus = true; 594}); 595$(document).on('mouseenter mouseleave', '.sub-content', function () { 596 topBarSubContentFocus = false; 597}); 598$(document).on('click', '.toggle-click', function () { 599 $(this).toggleClass('active'); 600}); 601$(document).on('blur', '.toggle-click', function () { 602 if (topBarSubContentFocus === false) { 603 $(this).removeClass('active'); 604 } 605}); 606$(document).on('click', '.sub-content', function () { 607 $('.toggle-click').focus(); 608}); // User Dropdown 609 610$(document).on('mouseenter', '.fnToggleUserDropdown', function () { 611 var target = $('#userDropdownPlaceholder'); 612 var trigger = $(this); 613 target.html('<img src="/content/images/loader.gif" style="margin-left:50%" />'); 614 $.get('/Partial/topBarUserDropdown', function (data) { 615 target.html(data); 616 trigger.removeClass('fnToggleUserDropdown'); 617 }); 618}); //#endregion 619}(); 620// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 621!function() { 622$(document).on('click', '[data-toggle="toggle"]', function (e) { 623 var target = $(this).data("target"); 624 625 if (!target) { 626 return; 627 } 628 629 e.preventDefault(); 630 $(target).toggle(); 631}); 632$(document).on('click', '[data-toggle="slide"]', function (e) { 633 var target = $(this).data("target"); 634 635 if (!target) { 636 return; 637 } 638 639 e.preventDefault(); 640 $(target).slideToggle(400); 641}); 642}(); 643// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 644!function() { 645// creates js support for "{0}".format("yeah"); 646// First, checks if it isn't implemented yet. 647if (!String.prototype.format) { 648 String.prototype.format = function () { 649 var args = arguments; 650 return this.replace(/{(\d+)}/g, function (match, number) { 651 return typeof args[number] !== 'undefined' ? args[number] : match; 652 }); 653 }; 654} 655}(); 656// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 657!function() { 658// Multiple dropdowns (e.g. Country > State ) 659// Clear options in secondary select dropdowns 660// Used in: \Scripts\core\advertise.js 661// Used in: \Scripts\core\global.js 662// Used in: \Views\Eventhome2\index.vm 663// Used in: \Views\Registration\mobileapp.vm 664function subOptions(obj) { 665 obj.options.length = 0; 666} // Refresh secondary select dropdowns 667// Used in: \Scripts\core\advertise.js 668// Used in: \Scripts\core\global.js 669// Used in: \Views\Eventhome2\index.vm 670// Used in: \Views\Registration\mobileapp.vm 671 672 673function addOption(obj, value, text) { 674 var optionP = document.createElement('option'); 675 optionP.text = text; 676 optionP.value = value; 677 678 try { 679 obj.add(optionP, null); 680 } catch (ex) { 681 obj.add(optionP); 682 } 683} 684}(); 685// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 686!function() { 687// Default options for jQuery validate on Bootstrap Forms 688window.bootstrapValidateOptions = { 689 highlight: function (element) { 690 var formGroup = $(element).closest('form > .form-group'); 691 692 if ($(element).parent().not('.form-group')) { 693 $(element).closest('.form-group').addClass('has-error'); 694 } else { 695 formGroup.addClass('has-error'); 696 } // hide normal help text when error is shown instead. Adding a class so we which one to show again. 697 698 699 formGroup.find('p.help-block').addClass('validate-hide').hide(); 700 }, 701 unhighlight: function (element) { 702 var formGroup = $(element).closest('form > .form-group'); 703 704 if ($(element).parent().not('.form-group')) { 705 $(element).closest('.form-group').removeClass('has-error'); 706 } else { 707 formGroup.removeClass('has-error'); 708 } // show normal help text when error is removed 709 710 711 formGroup.find('p.validate-hide').show(); 712 }, 713 errorElement: 'span', 714 errorClass: 'help-block', 715 errorPlacement: function (error, element) { 716 if (element.parent('.bootstrap-select').length) { 717 error.insertAfter(element.parent()); 718 return; 719 } 720 721 if (element.parent('.input-group').length) { 722 error.insertAfter(element.parent()); 723 return; 724 } 725 726 if (element.parent('label').length) { 727 if (element.parent('label').parent('.checkbox').length === 1) { 728 element.closest('.form-group').append(error); 729 return; 730 } 731 732 error.insertAfter(element.parent()); 733 return; 734 } 735 736 if (element.is(':hidden')) { 737 error.insertAfter(element.next()); 738 } // When using .float-label-control the label is placed after the input. 739 740 741 if (element.next('label').length) { 742 error.insertAfter(element.next('label')); 743 } else { 744 error.insertAfter(element); 745 } 746 } 747}; 748}(); 749// This entry need to be wrapped in an IIFE because it need to be in strict mode. 750!function() { 751"use strict"; 752/* harmony import */ var _Scripts_bloc_webapi_upload_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(327); 753/* harmony import */ var _Scripts_bloc_webapi_upload_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_Scripts_bloc_webapi_upload_js__WEBPACK_IMPORTED_MODULE_0__); 754 755const palette = ['#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#ffff00', '#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#fff2ca', '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#ffe694', '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#b7dde8', '#fac08f', '#f2c314', '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#92cddc', '#e36c09', '#c09100', '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#31859b', '#974806', '#7f6000']; 756const froalaCommonOptions = { 757 //key: '2J1B10dC4C4B4D3D4H3cWHNGGDTCWHId1Eb1Oc1Yh1b2Ld1POkE3D3F3B8A4A4F5G3B2G2==', 758 key: '2J1B10dC4C4B4D3D4H3cWHNGGDTCWHId1Eb1Oc1Yh1b2Ld1POkF3D3F3B7A4A4F5G3B2G2==', 759 attribution: false, 760 saveInterval: 0, 761 typingTimer: 200, 762 // Typography 763 paragraphFormat: { 764 N: 'Normal', 765 PRE: 'Code', 766 H1: 'Heading 1', 767 H2: 'Heading 2', 768 H3: 'Heading 3', 769 H4: 'Heading 4', 770 H5: 'Heading 5', 771 H6: 'Heading 6' 772 }, 773 fontSizeUnit: 'rem', 774 fontSize: ['1', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.8', '1.9', '2', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.8', '2.9', '3', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.8', '3.9', '4', '4.1', '4.2', '4.3', '4.4', '4.5', '4.6', '4.8', '4.9', '5', '5.1', '5.2', '5.3', '5.4', '5.5', '5.6', '5.8', '5.9', '6', '6.1', '6.2', '6.3', '6.4', '6.5', '6.6', '6.8', '6.9', '7', '7.1', '7.2', '7.3', '7.4', '7.5', '7.6', '7.8', '7.9', '8', '8.1', '8.2', '8.3', '8.4', '8.5', '8.6', '8.8', '8.9'], 775 paragraphStyles: { 776 'text-muted': "<span class='text-muted'>Muted text</span>", 777 'text-primary': "<span class='text-primary'>Primary text</span>", 778 'text-success': "<span class='text-success'>Success text</span>", 779 'text-info': "<span class='text-info'>Info text</span>", 780 'text-warning': "<span class='text-warning'>Warning text</span>", 781 'text-danger': "<span class='text-danger'>Danger text</span>", 782 'text-capitalize': "<span class='text-capitalize'>Capitalized text</span>", 783 'text-lowercase': "<span class='text-lowercase'>Lowercased text</span>", 784 'text-uppercase': "<span class='text-uppercase'>Uppercased text</span>" 785 }, 786 // Text colors
787 colorsBackground: palette, 788 colorsText: palette, 789 colorsStep: 11, 790 imageStyles: { 791 'img-rounded': 'Rounded', 792 'img-thumbnail': 'Thumbnail' 793 }, 794 // Table 795 tableStyles: { 796 'table-bordered': 'Bordered table', 797 'table-striped': 'Striped', 798 'table-condensed': 'Condensed' 799 }, 800 linkEditButtons: ['linkOpen', 'linkStyle', 'linkEdit', 'linkRemove'], 801 linkInsertButtons: ['linkBack'], 802 linkMultipleStyles: false, 803 linkStyles: { 804 'inherit': 'Default', 805 'no-underline': 'No underline', 806 'btn btn-primary': 'Primary button', 807 'btn btn-success': 'Success button', 808 'btn btn-info': 'Info button', 809 'btn btn-warning': 'Warning button', 810 'btn btn-danger': 'Danger button', 811 'btn btn-default': 'Default button' 812 }, 813 tableColors: palette, 814 tableColorsStep: 11, 815 // Image upload 816 imageDefaultWidth: 0, 817 // Opplasting gÃ¥r via Bloc.WebAPI (JWT) i image.beforeUpload/file.beforeUpload under â 818 // se Scripts/bloc-webapi-upload.js. Den anonyme uploader.bloc.net er avviklet (2026-09). 819 imageMaxSize: 1024 * 1024 * 15, 820 // 15m bytes 821 // File upload 822 fileMaxSize: 1024 * 1024 * 15, 823 // Video upload 824 videoUpload: false, 825 wordPasteModal: true, 826 wordAllowedStyleProps: [//'font-family', 827 //'font-size', 828 'background', 'color', 'width', 'text-align', 'vertical-align', 'background-color', 'text-decoration', 'font-weight', 'font-style'], 829 events: { 830 'contentChanged': function (inputEvent) { 831 $(this.$el).trigger('change'); 832 }, 833 'image.beforeUpload': function (images) { 834 return window.BlocWebApiUpload.froalaImageBeforeUpload.call(this, images); 835 }, 836 'file.beforeUpload': function (files) { 837 return window.BlocWebApiUpload.froalaFileBeforeUpload.call(this, files); 838 }, 839 'image.error': function (error) { 840 $('.fr-popup.fr-active').find('h3').text(error.message); 841 }, 842 'table.inserted': function (table) { 843 $(table).addClass('table table-bordered').wrap('<div class="table-responsive"></div>'); 844 }, 845 'save.error': function (editor, response) { 846 alert('Something went wrong when saving your text. Please try again.'); 847 }, 848 'commands.after': function (cmd, p1, p2) { 849 if (cmd == 'linkStyle' && p1.includes('btn')) { 850 const classListNow = this.selection.element().classList; 851 852 if (classListNow.length == 1) { 853 // Only the btn class is present, remove it: 854 classListNow.remove('btn'); 855 } 856 } 857 } 858 } 859}; 860const froalaDefaultOptions = { 861 language: Site.froalaLangCode != '' ? Site.froalaLangCode : null, 862 toolbarButtons: ['fullscreen', 'undo', 'redo', 'html', 'help', '-', 'paragraphFormat', 'paragraphStyle', '|', 'bold', 'italic', 'underline', 'strikeThrough', 'align', 'clearFormatting', '|', 'formatOL', 'formatUL', '|', 'textColor', 'backgroundColor', 'fontSize', '|', 'insertImage', 'insertVideo', 'embedly', 'insertFile', 'insertTable', 'insertLink', 'insertHR'], 863 pluginsEnabled: ['align', 'codeBeautifier', 'codeView', 'colors', 'draggable', 'entities', 'file', 'fontSize', 'image', 'lineBreaker', 'link', 'lists', 'paragraphFormat', 'paragraphStyle', 'quickInsert', 'quote', 'table', 'url', 'video', 'wordPaste', 'fullscreen', 'help', 'embedly'], 864 quickInsertButtons: ['image', 'video', 'table'], 865 // Image Edit 866 imageEditButtons: ['imageReplace', 'imageAlign', 'imageCaption', 'imageRemove', '|', 'imageLink', 'linkOpen', 'linkEdit', 'linkRemove', '-', 'imageDisplay', 'imageStyle', 'imageAlt', 'imageSize'], 867 htmlRemoveTags: ['script'], 868 htmlAllowedEmptyTags: ['textarea', 'a', 'iframe', 'object', 'video', 'style', 'script', '.fa', 'span', 'p', 'path', 'line', 'g', 'svg'], 869 htmlAllowedTags: ['.*'], 870 htmlUntouched: true, 871 htmlAllowedAttrs: ['accept', 'accept-charset', 'accesskey', 'action', 'align', 'allowfullscreen', 'allowtransparency', 'alt', 'aria-.*', 'async', 'autocomplete', 'autofocus', 'autoplay', 'autosave', 'background', 'bgcolor', 'border', 'charset', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'color', 'cols', 'colspan', 'content', 'contenteditable', 'contextmenu', 'controls', 'coords', 'data', 'data-.*', 'datetime', 'default', 'defer', 'dir', 'dirname', 'disabled', 'download', 'draggable', 'dropzone', 'enctype', 'for', 'form', 'formaction', 'frameborder', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'http-equiv', 'icon', 'id', 'ismap', 'itemprop', 'keytype', 'kind', 'label', 'lang', 'language', 'list', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'mozallowfullscreen', 'multiple', 'muted', 'name', 'novalidate', 'open', 'optimum', 'pattern', 'ping', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'reversed', 'rows', 'rowspan', 'sandbox', 'scope', 'scoped', 'scrolling', 'seamless', 'selected', 'shape', 'size', 'sizes', 'span', 'src', 'srcdoc', 'srclang', 'srcset', 'start', 'step', 'summary', 'spellcheck', 'style', 'tabindex', 'target', 'title', 'type', 'translate', 'usemap', 'value', 'valign', 'webkitallowfullscreen', 'width', 'wrap'], 872 pasteAllowedStyleProps: [], 873 pasteDeniedAttrs: ['class', 'id', 'style'] 874}; 875const froalaInlineOptions = { 876 initOnClick: false, 877 toolbarInline: true, 878 charCounterCount: false, 879 language: Site.froalaLangCode != '' ? Site.froalaLangCode : null, 880 htmlUntouched: true, 881 htmlAllowedAttrs: ['accept', 'accept-charset', 'accesskey', 'action', 'align', 'allowfullscreen', 'allowtransparency', 'alt', 'aria-.*', 'async', 'autocomplete', 'autofocus', 'autoplay', 'autosave', 'background', 'bgcolor', 'border', 'charset', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'color', 'cols', 'colspan', 'content', 'contenteditable', 'contextmenu', 'controls', 'coords', 'data', 'data-.*', 'datetime', 'default', 'defer', 'dir', 'dirname', 'disabled', 'download', 'draggable', 'dropzone', 'enctype', 'for', 'form', 'formaction', 'frameborder', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'http-equiv', 'icon', 'id', 'ismap', 'itemprop', 'keytype', 'kind', 'label', 'lang', 'language', 'list', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'mozallowfullscreen', 'multiple', 'muted', 'name', 'novalidate', 'open', 'optimum', 'pattern', 'ping', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'reversed', 'rows', 'rowspan', 'sandbox', 'scope', 'scoped', 'scrolling', 'seamless', 'selected', 'shape', 'size', 'sizes', 'span', 'src', 'srcdoc', 'srclang', 'srcset', 'start', 'step', 'summary', 'spellcheck', 'style', 'tabindex', 'target', 'title', 'type', 'translate', 'usemap', 'value', 'valign', 'webkitallowfullscreen', 'width', 'wrap'], 882 toolbarButtons: ['paragraphFormat', 'paragraphStyle', '|', 'bold', 'italic', 'underline', 'strikeThrough', 'align', '-', 'formatO
882L', 'formatUL', '|', 'textColor', 'backgroundColor', 'fontSize', '-', 'insertImage', 'insertVideo', 'insertFile', 'insertTable', 'insertLink', 'insertHR'], 883 pluginsEnabled: ['align', 'codeBeautifier', 'codeView', 'colors', 'draggable', 'entities', 'file', 'fontSize', 'image', 'lineBreaker', 'link', 'lists', 'paragraphFormat', 'paragraphStyle', 'quickInsert', 'quote', 'table', 'url', 'video', 'wordPaste', 'fullscreen', 'help', 'save'], 884 // fontSize: [ 885 // '8','9','10','11','12','14','16','18','20','22','24','26','28','30','36','48','60','72','96', 886 // ], 887 quickInsertButtons: ['image', 'video', 'table'], 888 // Image Edit 889 imageEditButtons: ['imageReplace', 'imageAlign', 'imageCaption', 'imageRemove', '|', 'imageLink', 'linkOpen', 'linkEdit', 'linkRemove', '-', 'imageDisplay', 'imageStyle', 'imageAlt', 'imageSize'], 890 pasteAllowedStyleProps: [], 891 pasteDeniedAttrs: ['class', 'id', 'style'] 892}; 893const froalaBasicOptions = { 894 language: Site.froalaLangCode != '' ? Site.froalaLangCode : null, 895 toolbarButtons: ['help', 'html', '|', 'bold', 'italic', 'underline', 'align', '|', 'insertLink'], 896 pluginsEnabled: ['align', 'codeBeautifier', 'codeView', 'colors', 'draggable', 'entities', 'file', 'fontSize', 'image', 'lineBreaker', 'link', 'lists', 'paragraphFormat', 'paragraphStyle', 'quickInsert', 'quote', 'table', 'url', 'video', 'wordPaste', 'fullscreen', 'help'], 897 quickInsertButtons: ['image', 'video', 'table'], 898 htmlUntouched: true, 899 htmlAllowedAttrs: ['accept', 'accept-charset', 'accesskey', 'action', 'align', 'allowfullscreen', 'allowtransparency', 'alt', 'aria-.*', 'async', 'autocomplete', 'autofocus', 'autoplay', 'autosave', 'background', 'bgcolor', 'border', 'charset', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'color', 'cols', 'colspan', 'content', 'contenteditable', 'contextmenu', 'controls', 'coords', 'data', 'data-.*', 'datetime', 'default', 'defer', 'dir', 'dirname', 'disabled', 'download', 'draggable', 'dropzone', 'enctype', 'for', 'form', 'formaction', 'frameborder', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'http-equiv', 'icon', 'id', 'ismap', 'itemprop', 'keytype', 'kind', 'label', 'lang', 'language', 'list', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'mozallowfullscreen', 'multiple', 'muted', 'name', 'novalidate', 'open', 'optimum', 'pattern', 'ping', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'reversed', 'rows', 'rowspan', 'sandbox', 'scope', 'scoped', 'scrolling', 'seamless', 'selected', 'shape', 'size', 'sizes', 'span', 'src', 'srcdoc', 'srclang', 'srcset', 'start', 'step', 'summary', 'spellcheck', 'style', 'tabindex', 'target', 'title', 'type', 'translate', 'usemap', 'value', 'valign', 'webkitallowfullscreen', 'width', 'wrap'], 900 pasteAllowedStyleProps: [], 901 pasteDeniedAttrs: ['class', 'id', 'style'] 902}; 903window.froalaDefaultOptions = { ...froalaCommonOptions, 904 ...froalaDefaultOptions 905}; // For use in widgets 906// 907 908window.froalaInlineOptions = { ...froalaCommonOptions, 909 ...froalaInlineOptions 910}; 911window.froalaBasicOptions = { ...froalaCommonOptions, 912 ...froalaBasicOptions 913}; 914}(); 915// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 916!function() { 917/* ----------------------------------------- 918COOKIES 919Replace with: http://jquery-howto.blogspot.com/2010/09/jquery-cookies-getsetdelete-plugin.html 920and http://code.google.com/p/cookies/wiki/Documentation 921-------------------------------------------*/ 922function getExpDate(days, hours, minutes) { 923 var expDate = new Date(); 924 925 if (typeof days === 'number' && typeof hours === 'number' && typeof hours === 'number') { 926 expDate.setDate(expDate.getDate() + parseInt(days, 10)); 927 expDate.setHours(expDate.getHours() + parseInt(hours, 10)); 928 expDate.setMinutes(expDate.getMinutes() + parseInt(minutes, 10)); 929 return expDate.toGMTString(); 930 } 931} // primary function to retrieve cookie by name 932 933 934function getCookie(name) { 935 var arg = name + '='; 936 var alen = arg.length; 937 var clen = document.cookie.length; 938 var i = 0; 939 940 while (i < clen) { 941 var j = i + alen; 942 943 if (document.cookie.substring(i, j) === arg) { 944 return getCookieVal(j); 945 } 946 947 i = document.cookie.indexOf('', i) + 1; 948 949 if (i === 0) { 950 break; 951 } 952 } 953 954 return ''; 955} // store cookie value with optional details as needed 956 957 958function setCookie(name, value, expires, path, domain, secure) { 959 document.cookie = name + '=' + encodeURIComponent(value) + (expires ? '; expires=' + expires : '') + (path ? '; path=' + path : '') + (domain ? '; domain=' + domain : '') + (secure ? '; secure' : ''); 960} // remove the cookie by setting ancient expiration date 961 962 963function deleteCookie(name, path, domain) { 964 if (getCookie(name)) { 965 document.cookie = name + '=' + (path ? '; path=' + path : '') + (domain ? '; domain=' + domain : '') + '; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; 966 } 967} // utility function called by getCookie( ) 968 969 970function getCookieVal(offset) { 971 var endstr = document.cookie.indexOf(';', offset); 972 973 if (endstr === -1) { 974 endstr = document.cookie.length; 975 } 976 977 return decodeURIComponent(document.cookie.substring(offset, endstr)); 978} 979 980window.getExpDate = getExpDate; 981window.getCookie = getCookie; 982window.setCookie = setCookie; 983window.deleteCookie = deleteCookie; 984window.getCookieVal = getCookieVal; 985}(); 986// This entry need to be wrapped in an IIFE because it need to be isolated against other entry modules. 987!function() { 988window.onunhandledrejection = function (event) { 989 console.warn('UNHANDLED PROMISE REJECTION:' + event.reason); 990}; // Polyfill for IE11 991// Needed for IE11 to understand CustomEvent in AssetHelper.renderAssetsDirectly 992 993 994; 995 996(function () { 997 if (typeof window.CustomEvent === 'function') return false;
998 999 function CustomEvent(event, params) { 1000 params = params || { 1001 bubbles: false, 1002 cancelable: false, 1003 detail: undefined 1004 }; 1005 var evt = document.createEvent('CustomEvent'); 1006 evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); 1007 return evt; 1008 } 1009 1010 CustomEvent.prototype = window.Event.prototype; 1011 window.CustomEvent = CustomEvent; 1012})(); 1013 1014function isMyScriptLoaded(url) { 1015 if (!url) return false; 1016 var scripts = document.getElementsByTagName('script'); 1017 1018 for (var i = scripts.length; i--;) { 1019 if (scripts[i].getAttribute('src') == url) { 1020 return true; 1021 } 1022 } 1023 1024 return false; 1025} 1026 1027window.isMyScriptLoaded = isMyScriptLoaded; // Seems we cant bind a listener to script.onload event after it's appendend/before its finished loading. 1028 1029function addLoadEvent(e, f) { 1030 var old = e.onload; 1031 1032 if (typeof e.onload != 'function') { 1033 e.onload = f; 1034 } else { 1035 e.onload = function () { 1036 if (old) { 1037 old(); 1038 } 1039 1040 f(); 1041 }; 1042 } 1043} // Check for features we need 1044 1045 1046function browserSupportsAllFeatures() { 1047 return window.Promise; // && window.fetch && window.Symbol; 1048} 1049 1050function checkScript(url) { 1051 var arr = document.scripts; 1052 var i = 0; 1053 1054 for (i = 0; i < arr.length; i++) { 1055 if (arr[i].getAttribute('src') === url) { 1056 return arr[i]; 1057 } 1058 } 1059} // only used for polyfill 1060 1061 1062function loadScript(src, done) { 1063 var x = document.getElementsByTagName('head')[0]; 1064 var s = document.createElement('script'); 1065 s.src = src; 1066 1067 s.onload = function () { 1068 done(); 1069 }; 1070 1071 s.onerror = function () { 1072 done(new Error('Failed to load script ' + src)); 1073 }; 1074 1075 x.appendChild(s); 1076} 1077 1078window.loadScript = loadScript; 1079 1080if (browserSupportsAllFeatures()) { 1081 revealPromiseFunctions(); 1082} else { 1083 loadScript('/scripts/_polyfills/es6-promise.bundle.js', revealPromiseFunctions); 1084} 1085 1086function revealPromiseFunctions(err) { 1087 return window.loadScript = function (url) { 1088 return new Promise(function (resolve, reject) { 1089 var script = checkScript(url); 1090 1091 if (typeof script !== 'undefined') { 1092 if (script.classList.contains('loading')) { 1093 addLoadEvent(script, resolve); 1094 } else { 1095 resolve(); 1096 } 1097 1098 return false; 1099 } 1100 1101 var x = document.getElementsByTagName('head')[0]; 1102 var s = document.createElement('script'); 1103 s.async = true; 1104 s.src = url; 1105 s.className = 'loading'; 1106 addLoadEvent(s, resolve); 1107 addLoadEvent(s, function () { 1108 s.className = ''; 1109 }); 1110 s.onerror = reject; 1111 x.appendChild(s); 1112 }); 1113 }; 1114} 1115}(); 1116/******/ })() 1117;
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.