PageSourceSearch

https://www.sleddog.no/js/bloc-primer.js?v=2

js sleddog.no collected 2026-10-02 13:25:01 UTC 39,477 bytes, 1,117 lines download raw bytes

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.