From 8b88a2b854edb06ab5c047d510f700d6fb256f66 Mon Sep 17 00:00:00 2001 From: Fabian Pichler Date: Fri, 31 Jul 2026 23:24:00 +0200 Subject: [PATCH 1/2] CELDEV-1332 Add message API endpoints --- celements-webapp/Jenkinsfile.release | 1 + celements-webapp/pom.xml | 4 + .../webapp/resources/celJS/initCelements.js | 8 +- .../resources/celJS/initCelements.min.js | 2 +- .../main/webapp/resources/celJS/validation.js | 8 +- .../templates/celAjax/FlowplayerInOverlay.vm | 1 + .../celMacros/startCelementsDocument.vm | 2 + .../src/main/webapp/templates/htmlheader.vm | 2 + component/pom.xml | 80 +++++++++++++++ .../celements/web/api/MessagesController.java | 70 +++++++++++++ .../web/api/MessagesControllerTest.java | 97 +++++++++++++++++++ 11 files changed, 262 insertions(+), 13 deletions(-) create mode 100644 component/pom.xml create mode 100644 component/src/main/java/com/celements/web/api/MessagesController.java create mode 100644 component/src/test/java/com/celements/web/api/MessagesControllerTest.java diff --git a/celements-webapp/Jenkinsfile.release b/celements-webapp/Jenkinsfile.release index 833677251..6ee2a72fa 100644 --- a/celements-webapp/Jenkinsfile.release +++ b/celements-webapp/Jenkinsfile.release @@ -67,6 +67,7 @@ releasePipeline(manifest: [ 'celements-rte-tiny6-war', 'celements-rte-langs-tiny4-war', 'celements-rte-langs-tiny6-war', + 'celements-web-component-jar', 'celements-webapp-war', ], ]) diff --git a/celements-webapp/pom.xml b/celements-webapp/pom.xml index e13101feb..a4302ff84 100644 --- a/celements-webapp/pom.xml +++ b/celements-webapp/pom.xml @@ -244,6 +244,10 @@ com.celements celements-spring-mvc + + com.celements + celements-web-component + com.celements celements-spring-security diff --git a/celements-webapp/src/main/webapp/resources/celJS/initCelements.js b/celements-webapp/src/main/webapp/resources/celJS/initCelements.js index dcd2c76c7..499ad4c70 100644 --- a/celements-webapp/src/main/webapp/resources/celJS/initCelements.js +++ b/celements-webapp/src/main/webapp/resources/celJS/initCelements.js @@ -484,12 +484,8 @@ window.celMessages.isLoaded = false; try { - new Ajax.Request(window.getCelHost(), { - method: 'post', - parameters: { - xpage: 'celements_ajax', - ajax_mode: 'Messages', - }, + new Ajax.Request(document.querySelector('meta[name="celements-messages-url"]').content, { + method: 'get', onSuccess: function (transport) { if (transport.responseText.isJSON()) { const newMessages = transport.responseText.evalJSON(); diff --git a/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js b/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js index 950a42f9e..c44e643cc 100644 --- a/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js +++ b/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js @@ -1 +1 @@ -(function (window, undefined) { "use strict"; if (typeof window.console === "undefined") { window.console = {} } if (typeof window.console.error === "undefined") { window.console.error = Prototype.emptyFunction } if (typeof window.console.warn === "undefined") { window.console.warn = window.console.error } if (typeof window.console.info === "undefined") { window.console.info = window.console.warn } if (typeof window.console.log === "undefined") { window.console.log = window.console.info } if (typeof window.console.debug === "undefined") { window.console.debug = window.console.log } if (typeof window.CELEMENTS === "undefined") { window.CELEMENTS = {} } if (typeof window.CELEMENTS.mixins === "undefined") { window.CELEMENTS.mixins = {} } if (typeof window.CELEMENTS.mixins.Event === "undefined") { window.CELEMENTS.mixins.Event = Class.create({ memo: undefined, stopped: undefined, eventName: undefined, type: undefined, detail: undefined, cancelable: undefined, defaultPrevented: undefined, target: undefined, initialize: function (eventName, memo, target) { this.memo = memo; this.eventName = eventName; this.stopped = false; this.type = eventName; this.detail = memo; this.cancelable = true; this.defaultPrevented = false; this.target = target || (memo ? memo.target : null) }, stop: function () { if (this.cancelable) { this.stopped = true; this.defaultPrevented = true } }, preventDefault: function () { this.stop() }, findElement: function () { return this.target } }) } if (typeof window.CELEMENTS.mixins.Observable === "undefined") { window.CELEMENTS.mixins.Observable = { _celEventMap: null, _getCelEventMap: function (eventKey) { if (!this._celEventMap) { this._celEventMap = new Map } if (eventKey) { if (!this._celEventMap.has(eventKey)) { this._celEventMap.set(eventKey, []) } return this._celEventMap.get(eventKey) } return this._celEventMap }, celObserve: function (eventKey, callbackFN) { console.debug("cel celObserve:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celObserve call" } this._getCelEventMap(eventKey).push(callbackFN) }, celStopObserving: function (eventKey, callbackFN) { console.debug("cel celStopObserving:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celStopObserving call" } this._getCelEventMap().set(eventKey, this._getCelEventMap(eventKey).filter(function (fn) { return fn !== callbackFN })) }, celFire: function (eventKey, memo) { if (!eventKey) { throw "undefined eventKey in celFire call" } const event = new CELEMENTS.mixins.Event(eventKey, memo, this); const listeners = this._getCelEventMap(eventKey); console.debug("cel celFire:", event, "on", listeners); listeners.forEach(function (callbackFN) { try { callbackFN(event) } catch (exp) { console.error("listener in celFire failed for event", eventKey, callbackFN, exp) } }); return event } } } let celOnBeforeLoadListenerArray = []; window.celAddOnBeforeLoadListener = function (listenerFunc) { console.warn("celAddOnBeforeLoad is deprecated since open-celements 5.4 / January 2022." + ' Instead register a listener on "DOMContentLoaded"', listenerFunc); celOnBeforeLoadListenerArray.push(listenerFunc) }; document.addEventListener("DOMContentLoaded", function () { celOnBeforeLoadListenerArray.forEach(function (listener) { try { listener() } catch (e) { console.error("Listener for celOnBeforeLoad failed: ", e) } }); $(document.body).fire("celements:beforeOnLoad") }); let celOnFinishHeaderListenerArray = []; window.celAddOnFinishHeaderListener = function (listenerFunc) { celOnFinishHeaderListenerArray.push(listenerFunc) }; window.celFinishHeaderHandler = function () { celOnFinishHeaderListenerArray.forEach(function (listener) { try { listener() } catch (exp) { console.error("Failed to execute celOnFinishHeader listener. ", exp) } }) }; if (typeof window.getCelDomain === "undefined") { window.getCelDomain = function () { const hostName = window.location.host; return hostName.replace(/^www\./, "") } } if (typeof window.CELEMENTS.LoadingIndicator === "undefined") { window.CELEMENTS.LoadingIndicator = Class.create({ _loadingImg: undefined, initialize: function () { const _me = this; _me._loadingImg = new Hash }, getLoadingIndicator: function (isSmallOrPxSize) { const _me = this; let loaderType = "ajax-loader-32px"; if (typeof isSmallOrPxSize === "boolean") { if (isSmallOrPxSize) { loaderType = "ajax-loader-16px" } } else if (typeof isSmallOrPxSize === "number") { loaderType = "ajax-loader-" + isSmallOrPxSize + "px" } if (!_me._loadingImg.get(loaderType)) { _me._loadingImg.set(loaderType, new Element("img", { src: CELEMENTS.getUtils().getPathPrefix() + "/file/resources/celRes/spinner/" + loaderType + ".png", class: "editorLoading", alt: "loading..." })) } return _me._loadingImg.get(loaderType).clone() } }) } if (typeof window.CELEMENTS.Utils === "undefined") { window.CELEMENTS.Utils = Class.create({ _srcOriginHost: undefined, getPathPrefix: function () { const _me = this; if (!_me._srcOriginHost) { let srcOriginHost = null; const scripts = document.getElementsByTagName("script"); let len = scripts.length; const re = new RegExp("(https?://[^/]*)/(([^/]*/)*)resources/celJS/initCelements(.min)?\\.js(\\?.*)?$"); let src; while (len--) { src = scripts[len].src; const srcMatches = src.match(re); if (src && srcMatches) { srcOriginHost = srcMatches[1]; const prefixPath = srcMatches[2]; const prefixPathSplit = prefixPath.split("/"); const prefixStr = prefixPathSplit.splice(0, prefixPathSplit.length - 2).join("/"); if (prefixStr != "") { srcOriginHost += "/" + prefixStr } break } } console.log("getPathPrefix computed prefixPath: ", srcOriginHost); _me._srcOriginHost = srcOriginHost } return _me._srcOriginHost }, convertFullNameToViewURL: function (fullName) { const _me = this; return _me.getPathPrefix() + ("/" + fullName.replace(/\./, "/")).replace(/\/Content\//, "/") } }); const globalUtilsInstance = new window.CELEMENTS.Utils; window.CELEMENTS.getUtils = function () { return globalUtilsInstance } } if (typeof window.CELEMENTS.getPathPrefix === "undefined") { window.CELEMENTS.getPathPrefix = function () { console.warn("deprecated call of window.CELEMENTS.getPathPrefix." + " Instead use window.CELEMENTS.getUtils().getPathPrefix()"); return window.CELEMENTS.getUtils().getPathPrefix() } } if (typeof window.getCelHost === "undefined") { window.getCelHost = function () { let celHost = document.location + "?"; if (document.location.pathname.indexOf("/skin/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/skin/resources/")) } else if (document.location.pathname.indexOf("/file/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/file/resources/")) } else { celHost = celHost.substring(0, celHost.indexOf("?")) } return celHost } } if (typeof window.CELEMENTS.Ajax === "undefined") { window.CELEMENTS.Ajax = {} } if (typeof window.CELEMENTS.Ajax.Reconnector === "undefined") { window.CELEMENTS.Ajax.Reconnector = Class.create({ _htmlElem: undefined, _callbackOnSuccess: undefined, _reconnectWait: undefined, _reconnectorHandlerBind: undefined, _cancelAjaxOnTimeoutBind: undefined, _reconnectorExecuter: undefined, _reconnectWaitStart: undefined, _minReconnectWait: undefined, _maxReconnectWait: undefined, _url: undefined, _configObj: undefined, initialize: function (htmlElemId, callbackOnSuccess, configObj) { const _me = this; _me._htmlElem = $(htmlElemId); _me._configObj = configObj || {}; _me._url = _me._configObj.url || window.getCelHost(); _me._callbackOnSuccess = callbackOnSuccess; _me._reconnectorHandlerBind = _me._reconnectorHandler.bind(_me); _me._cancelAjaxOnTimeoutBind = _me._cancelAjaxOnTimeout.bind(_me); _me._minReconnectWait = _me._configObj.minReconnectWait || 10; _me._maxReconnectWait = _me._configObj.maxReconnectWait || 30; _me._reset() }, _reset: function () { const _me = this; _me._reconnectWaitStart = _me._minReconnectWait }, setMinRecconectWait: function (minReconnectWait) { const _me = this; _me._minReconnectWait = minReconnectWait }, setMaxRecconectWait: function (maxReconnectWait) { const _me = this; _me._maxReconnectWait = maxReconnectWait }, _fireAjaxRecconectTrying: function () { const _me = this; return _me._htmlElem.fire("celements:AjaxReconnectTrying", _me._reconnectWait) }, _reconnectorHandler: function () { const _me = this; _me._reconnectWait--; if (_me._reconnectWait == 0) { _me._reconnectorExecuter.stop(); if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Trying..."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryNotice } _me._htmlElem.update(mesg) } _me._connectionTester() } else { if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Retrying in {} seconds."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryDelayNotice } mesg = mesg.replace("{}", _me._reconnectWait); _me._htmlElem.update(mesg); _me._htmlElem.fire("celements:AjaxReconnectFailed") } } }, start: function () { const _me = this; _me._reconnectWait = _me._reconnectWaitStart; _me._reconnectorExecuter = new PeriodicalExecuter(_me._reconnectorHandlerBind, 1) }, _cancelAjaxOnTimeout: function (ajaxCall) { if (!ajaxCall._complete) { ajaxCall.transport.abort() } }, _connectionTester: function () { const _me = this; const connectionTestAjax = new Ajax.Request(_me._url, { parameters: { ajax: 1, xpage: "celements_ajax", ajax_mode: "pageTypeWithLayout", overwriteLayout: "SimpleLayout" }, onSuccess: function () { _me._reset(); _me._reconnectorExecuter = null; _me._callbackOnSuccess(); _me._htmlElem.fire("celements:AjaxReconnectSuccess") }, onFailure: function () { _me._reconnectWaitStart = Math.min(_me._reconnectWaitStart * 2, _me._maxReconnectWait); _me.start() } }); _me._cancelAjaxOnTimeoutBind.delay(10, connectionTestAjax) } }) } window.CELEMENTS.UrlUtils = Class.create({ getParams: function (search) { const _me = this; search = search || window.location.search; const paramSplit = search.split(new RegExp("[?&]")); paramSplit.unshift(new Hash); return paramSplit.reduce(_me._splitUriSearch.bind(_me)) || new Hash }, joinParams: function (hash) { let paramsArray = []; $H(hash).each(function (pair) { const pairMapped = pair.value.map(function (elem) { return pair.key + "=" + encodeURI(elem) }); paramsArray = paramsArray.concat(pairMapped) }); return paramsArray.join("&") }, _splitUriSearch: function (paramHash, elem) { let key = elem.split("=", 1); if (key.length > 0 && key[0].length > 0) { key = key[0]; const val = decodeURI(elem.substring(key.length + 1)); if (!paramHash.get(key)) { paramHash.set(key, [val]) } else { paramHash.get(key).push(val) } } return paramHash } }); window.celMessages = {}; window.celMessages.isLoaded = false; try { new Ajax.Request(window.getCelHost(), { method: "post", parameters: { xpage: "celements_ajax", ajax_mode: "Messages" }, onSuccess: function (transport) { if (transport.responseText.isJSON()) { const newMessages = transport.responseText.evalJSON(); console.log("initCelements.js: finished getting dictionary messages."); newMessages.isLoaded = true; window.celMessages = newMessages; celMessagesCbFnArray.each(function (callbackFn) { try { callbackFn(newMessages) } catch (exp) { console.error("Failed to execute callbackFn!", exp) } }); $(document.body).fire("cel:messagesLoaded", newMessages) } else { console.error("noJSON!!! ", transport.responseText) } } }) } catch (exp) { console.error("Failed to get Cel-Messages async!", exp) } const celMessagesCbFnArray = []; window.celExecOnceAfterMessagesLoaded = function (callbackFn) { if (!celMessagesCbFnArray.includes(callbackFn)) { celMessagesCbFnArray.push(callbackFn); if (window.celMessages.isLoaded) { callbackFn(window.celMessages) } } }; if (typeof window.CELEMENTS.CssClassEventHandler === "undefined") { window.CELEMENTS.CssClassEventHandler = Class.create({ _htmlElement: undefined, _eventName: undefined, _cssSelector: undefined, _className: undefined, _actionFunction: undefined, _conditionFunction: undefined, _actionHandlerBind: undefined, initialize: function (htmlElement, eventName, cssSelector, className, actionFunction, condition) { const _me = this; _me._htmlElement = $(htmlElement); _me._eventName = eventName; _me._cssSelector = cssSelector; _me._className = className; _me._actionFunction = actionFunction; if (condition && !/\s|;/.test(condition)) { _me._conditionFunction = new Function("me", "origin", "return " + condition + ";") } _me._actionHandlerBind = _me._actionHandler.bind(_me); _me._registerActionHandler() }, _registerActionHandler: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); Event.observe(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - register: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) }, _actionHandler: function (event) { const _me = this; _me._getTargetElements().each(function (targetElement) { if (!_me._conditionFunction || _me._conditionFunction(targetElement, _me._htmlElement)) { _me._actionFunction(targetElement, _me._className); console.debug("EventHandler - upon", _me._eventName, "action [", _me._actionFunction.name, _me._className, "] executed on", targetElement) } else { console.debug("EventHandler - action skipped for failed condition [", _me._conditionFunction, "] on ", targetElement) } }) }, _getTargetElements: function () { const _me = this; if (_me._cssSelector.startsWith("^")) { parent = _me._htmlElement.up(_me._cssSelector.substring(1)); return parent ? [parent] : [] } else { return $$(_me._cssSelector) } }, unregister: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - unregister: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) } }) } if (typeof window.CELEMENTS.EventManager === "undefined") { window.CELEMENTS.EventManager = Class.create({ _instructionRegex: new RegExp(/([\w:]+)([%+-])([\w-]+):([^?]+)\??(.+)?/), _actionFunctionMap: { "+": Element.addClassName, "-": Element.removeClassName, "%": Element.toggleClassName }, _eventElements: undefined, _eventElemCounter: undefined, _interpretDataCelEventBind: undefined, _contentChangedHandlerBind: undefined, _intersectionObserver: undefined, _intersectionValues: [], initialize: function () { const _me = this; _me._eventElements = new Array; _me._eventElemCounter = 0; _me._interpretDataCelEventBind = _me._interpretDataCelEvent.bind(_me); _me._contentChangedHandlerBind = _me._contentChangedHandler.bind(_me); try { _me._intersectionObserver = new IntersectionObserver(function (entries) { entries.forEach(_me._handleIntersection.bind(_me)) }, { threshold: [0, .5, 1] }) } catch (exp) { console.warn("EventManager - initialize: IntersectionObserver not available", exp) } }, _splitDataCelEventList: function (dataValue) { let ret = new Array; if (dataValue) { ret = dataValue.replace(/([^&])&([^&])/g, "$1#SPLIT#$2").split("#SPLIT#") } return ret }, _parseEventInstruction: function (instruction) { const _me = this; const parts = instruction.match(_me._instructionRegex) || []; const data = { eventName: parts[1], action: parts[2], className: parts[3], cssSelector: parts[4], condition: parts[5] }; if (data.eventName && data.action && data.className && data.cssSelector) { return data } else { throw "parseEventInstruction: unable to parse event instruction '" + instruction + "'" } }, _createEventHandler: function (htmlElem, instruction) { const _me = this; const data = _me._parseEventInstruction(instruction); const actionFunction = _me._actionFunctionMap[data.action]; if (actionFunction) { if (_me._intersectionObserver && (data.eventName.startsWith("cel:enter") || data.eventName.startsWith("cel:leave"))) { _me._intersectionObserver.observe(htmlElem); console.debug("EventManager - observing intersection", htmlElem.dataset.celEventNb, data) } return new window.CELEMENTS.CssClassEventHandler(htmlElem, data.eventName, data.cssSelector, data.className, actionFunction, data.condition) } else { throw "createEventHandler: unknown action '" + data.action + '"' } }, _createEventElement: function (htmlElem) { const _me = this; const dataValue = htmlElem.dataset.celEvent; return { htmlElem: htmlElem, dataValue: dataValue, eventHandlers: _me._splitDataCelEventList(dataValue).map(function (instruction) { try { return _me._createEventHandler(htmlElem, instruction) } catch (exp) { console.error("EventManager - interpretData: invalid instruction ", exp, htmlElem) } }).filter(Boolean) } }, _interpretDataCelEvent: function (htmlElem) { const _me = this; const logPref = "EventManager - interpretData: "; if (htmlElem.classList.contains("celOnEventInit")) { console.debug(logPref, "skip already initialized: ", htmlElem) } else if (htmlElem.up(".cel_template")) { console.debug(logPref, "skip template element: ", htmlElem) } else { htmlElem.dataset.celEventNb = ++_me._eventElemCounter; const newElem = _me._createEventElement(htmlElem); if (newElem.eventHandlers.length > 0) { _me._eventElements.push(newElem) } else { console.warn(logPref, "no valid instructions found on ", htmlElem) } htmlElem.classList.add("celOnEventInit"); $(htmlElem).fire("celEM:init") } }, _handleIntersection: function (entry) { const _me = this; const htmlElem = entry.target; const eventNb = htmlElem.dataset.celEventNb; const previous = _me._intersectionValues[eventNb] || Object.freeze({ y: Number.MAX_SAFE_INTEGER, ratio: 0 }); const current = Object.freeze({ y: entry.boundingClientRect.y, ratio: entry.intersectionRatio }); const direction = current.y > previous.y ? "up" : "down"; const type = entry.isIntersecting && current.ratio >= previous.ratio ? "enter" : "leave"; const ratioA = type === "enter" ? current.ratio : previous.ratio; const ratioB = type === "leave" ? current.ratio : previous.ratio; const steps = []; if (ratioA >= 1 && ratioB < 1) steps.push(":full"); if (ratioA >= .5 && ratioB < .5) steps.push(":half"); if (ratioA > 0 && ratioB <= 0) steps.push(""); steps.forEach(function (step) { ["cel:" + type + step, "cel:" + type + step + ":" + direction].forEach(function (eventName) { console.debug("EventManager - intersect", eventName, "on", eventNb, previous, "->", current); htmlElem.fire(eventName) }) }); _me._intersectionValues[eventNb] = current }, _contentChangedHandler: function (event) { const _me = this; console.debug("EventManager - contentChanged ", event); if (event.memo && event.memo.htmlElem) { _me.updateCelEventHandlers(event.memo.htmlElem) } else { _me.updateCelEventHandlers() } }, updateCelEventHandlers: function (htmlContainer) { const _me = this; const rootElem = htmlContainer || document.body; Event.stopObserving($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); Event.observe($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); _me._removeDisappearedElems(); rootElem.querySelectorAll(".celOnEvent").forEach(_me._interpretDataCelEventBind) }, _removeDisappearedElems: function () { const _me = this; for (let i = _me._eventElements.length - 1; i >= 0; i--) { const elem = _me._eventElements[i]; const isInBody = $(document.body).contains(elem.htmlElem); const changedDataValue = elem.htmlElem.dataset.celEvent !== elem.dataValue; if (!isInBody || changedDataValue || !elem.htmlElem.classList.contains("celOnEventInit")) { elem.eventHandlers.forEach(function (handler) { handler.unregister() }); _me._eventElements.splice(i, 1); elem.htmlElem.classList.remove("celOnEventInit"); console.debug("EventManager - removeDisappearedElem: ", elem) } } } }); window.CELEMENTS.globalEventManager = new window.CELEMENTS.EventManager; document.addEventListener("DOMContentLoaded", window.CELEMENTS.globalEventManager._contentChangedHandlerBind) } const formValidations = new Hash; const registerValidation = function (formElem) { if (formElem && formElem.id) { const valid = new Validation(formElem, { immediate: true, useTitles: true, stopOnFirst: false }); formValidations.set(formElem.id, valid) } else { console.error("failed to register validation on form with no id. ", formElem) } }; document.addEventListener("DOMContentLoaded", function () { $$("form.cel_form_validation").each(registerValidation); $(document.body).observe("cel_yuiOverlay:contentChanged", function (event) { const containerElem = event.findElement(); if (containerElem) { containerElem.select("form.cel_form_validation").each(registerValidation) } }) }); window.celAddOnFinishHeaderListener(function () { const metas = $$('meta[name="cel-GAA-Num"]'); if (metas.size() > 0 && metas[0].content != "") { const gaaNum = metas[0].content; if (gaaNum.startsWith("UA-")) { (function (i, s, o, g, r, a, m) { i["GoogleAnalyticsObject"] = r; i[r] = i[r] || function () { (i[r].q = i[r].q || []).push(arguments) }, i[r].l = 1 * new Date; a = s.createElement(o), m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) })(window, document, "script", "//www.google-analytics.com/analytics.js", "ga"); ga("create", gaaNum, window.getCelDomain()); ga("set", "anonymizeIp", true); ga("send", "pageview"); console.log("finish initalizing google universal analytics.", gaaNum) } else { (function (d, o, g, s, m) { s = d.createElement(o); m = d.getElementsByTagName(o)[0]; s.async = 1; s.src = g; m.parentNode.insertBefore(s, m) })(document, "script", "https://www.googletagmanager.com/gtag/js?id=" + gaaNum); window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments) } gtag("js", new Date); gtag("config", gaaNum); console.log("finish initalizing google analytics v4.", gaaNum) } } }); document.addEventListener("DOMContentLoaded", function () { if (typeof $j("img[usemap]").rwdImageMaps !== "undefined") { $j("img[usemap]").rwdImageMaps() } }); document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.presentation && CELEMENTS.presentation.getOverlayObj && CELEMENTS.presentation.getOverlayObj()) { CELEMENTS.presentation.getOverlayObj({ overlayLayout: "SimpleLayout" }).registerOpenHandler() } }); let mobileDim = null; const cel_updateOrientationCSSclasses = function () { const innerWidth = mobileDim.getInnerWidth(); const innerHeight = mobileDim.getInnerHeight(); if (innerWidth > innerHeight) { $(document.body).removeClassName("cel_orientation_portrait"); $(document.body).addClassName("cel_orientation_landscape") } else { $(document.body).removeClassName("cel_orientation_landscape"); $(document.body).addClassName("cel_orientation_portrait") } }; document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.mobile && CELEMENTS.mobile.Dimensions) { mobileDim = new CELEMENTS.mobile.Dimensions; Event.stopObserving(window, "orientationchange", cel_updateOrientationCSSclasses); Event.observe(window, "orientationchange", cel_updateOrientationCSSclasses) } }); const cel_initAllMultiselect = function (event) { console.debug("initAllMultiselect"); if ($j().multiselect != undefined) { $j(".celBootstrap,.celMultiselect").filter(":visible,.celForceMultiselect").each(function (index, element) { if (!$(element).up(".cel_template")) { console.debug("initAllMultiselect: ", element); cel_initAllMultiselect_element(element) } }) } else { console.debug("initAllMultiselect: bootstrap multiselect undefined") } }; const cel_initAllMultiselect_element = function (element) { let params = { numberDisplayed: 3, onDropdownHidden: cel_initAllMultiselect_onDropdownHidden, onChange: cel_initAllMultiselect_onChange }; let bootstrapCfg = element.getAttribute("data-bootstrapConfig"); if (!bootstrapCfg && element.getAttribute("data-multiselectAttr")) { bootstrapCfg = element.getAttribute("data-multiselectAttr"); console.warn("initAllMultiselect: deprecated data-multiselectAttr in use", element) } if (bootstrapCfg) { params = $j.extend(params, JSON.parse(bootstrapCfg)) } const multiselect = $j(element).multiselect(params); $(document.body).fire("cel:multiselectInitialized", { multiselect: multiselect }) }; const cel_initAllMultiselect_onDropdownHidden = function (event) { $j(event.target).css("display", ""); event.target.fire("cel:multiselectOnDropdownHidden") }; const cel_initAllMultiselect_onChange = function (option, checked, select) { const multiselectElement = this; console.debug("fire cel:multiselectOnChange on: ", multiselectElement); $(option[0]).fire("cel:multiselectOnChange", { multiselect: multiselectElement, checked: checked, select: select }) }; const cel_initAllMultiselect_tabMenuPanel = function (event) { $("tabMenuPanel").select(".celBootstrap,.celMultiselect").each(function (element) { if (element.visible()) { element.addClassName("celForceMultiselect") } }); cel_initAllMultiselect(event) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initMultiselect", cel_initAllMultiselect); $(document.body).stopObserving("celements:contentChanged", cel_initAllMultiselect); $(document.body).observe("cel:initMultiselect", cel_initAllMultiselect); $(document.body).observe("celements:contentChanged", cel_initAllMultiselect); if ($("tabMenuPanel")) { $("tabMenuPanel").stopObserving("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel); $("tabMenuPanel").observe("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel) } $(document.body).fire("cel:initMultiselect") }); const cel_addMaxDimToFluidImg = function (event) { $$("img.cel_fluidresizeWidth").each(function (imgElem) { imgElem.setStyle({ maxWidth: imgElem.readAttribute("width") + "px" }) }); $$("img.cel_fluidresizeHeight").each(function (imgElem) { imgElem.setStyle({ maxHeight: imgElem.readAttribute("height") + "px" }) }) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).stopObserving("celements:contentChanged", cel_addMaxDimToFluidImg); $(document.body).observe("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).observe("celements:contentChanged", cel_addMaxDimToFluidImg) }); document.addEventListener("DOMContentLoaded", function () { $$(".generalOverlayWrapper .generalOverlay .exitOnClose").each(function (elem) { elem.stopObserving("click", cel_closeOverlayWindow); elem.observe("click", cel_closeOverlayWindow) }) }); const cel_closeOverlayWindow = function (event) { event.stop(); window.close() }; const updateCelMessages = function () { if (typeof $j.format !== "undefined") { $j.format.locale({ date: celMessages.jqueryFormater }) } }; document.addEventListener("DOMContentLoaded", function () { if (window.celMessages.isLoaded && typeof celMessages.jqueryFormater === "object") { updateCelMessages() } else { $(document.body).observe("cel:messagesLoaded", updateCelMessages) } }) })(window); +(function (window, undefined) { "use strict"; if (typeof window.console === "undefined") { window.console = {} } if (typeof window.console.error === "undefined") { window.console.error = Prototype.emptyFunction } if (typeof window.console.warn === "undefined") { window.console.warn = window.console.error } if (typeof window.console.info === "undefined") { window.console.info = window.console.warn } if (typeof window.console.log === "undefined") { window.console.log = window.console.info } if (typeof window.console.debug === "undefined") { window.console.debug = window.console.log } if (typeof window.CELEMENTS === "undefined") { window.CELEMENTS = {} } if (typeof window.CELEMENTS.mixins === "undefined") { window.CELEMENTS.mixins = {} } if (typeof window.CELEMENTS.mixins.Event === "undefined") { window.CELEMENTS.mixins.Event = Class.create({ memo: undefined, stopped: undefined, eventName: undefined, type: undefined, detail: undefined, cancelable: undefined, defaultPrevented: undefined, target: undefined, initialize: function (eventName, memo, target) { this.memo = memo; this.eventName = eventName; this.stopped = false; this.type = eventName; this.detail = memo; this.cancelable = true; this.defaultPrevented = false; this.target = target || (memo ? memo.target : null) }, stop: function () { if (this.cancelable) { this.stopped = true; this.defaultPrevented = true } }, preventDefault: function () { this.stop() }, findElement: function () { return this.target } }) } if (typeof window.CELEMENTS.mixins.Observable === "undefined") { window.CELEMENTS.mixins.Observable = { _celEventMap: null, _getCelEventMap: function (eventKey) { if (!this._celEventMap) { this._celEventMap = new Map } if (eventKey) { if (!this._celEventMap.has(eventKey)) { this._celEventMap.set(eventKey, []) } return this._celEventMap.get(eventKey) } return this._celEventMap }, celObserve: function (eventKey, callbackFN) { console.debug("cel celObserve:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celObserve call" } this._getCelEventMap(eventKey).push(callbackFN) }, celStopObserving: function (eventKey, callbackFN) { console.debug("cel celStopObserving:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celStopObserving call" } this._getCelEventMap().set(eventKey, this._getCelEventMap(eventKey).filter(function (fn) { return fn !== callbackFN })) }, celFire: function (eventKey, memo) { if (!eventKey) { throw "undefined eventKey in celFire call" } const event = new CELEMENTS.mixins.Event(eventKey, memo, this); const listeners = this._getCelEventMap(eventKey); console.debug("cel celFire:", event, "on", listeners); listeners.forEach(function (callbackFN) { try { callbackFN(event) } catch (exp) { console.error("listener in celFire failed for event", eventKey, callbackFN, exp) } }); return event } } } let celOnBeforeLoadListenerArray = []; window.celAddOnBeforeLoadListener = function (listenerFunc) { console.warn("celAddOnBeforeLoad is deprecated since open-celements 5.4 / January 2022." + ' Instead register a listener on "DOMContentLoaded"', listenerFunc); celOnBeforeLoadListenerArray.push(listenerFunc) }; document.addEventListener("DOMContentLoaded", function () { celOnBeforeLoadListenerArray.forEach(function (listener) { try { listener() } catch (e) { console.error("Listener for celOnBeforeLoad failed: ", e) } }); $(document.body).fire("celements:beforeOnLoad") }); let celOnFinishHeaderListenerArray = []; window.celAddOnFinishHeaderListener = function (listenerFunc) { celOnFinishHeaderListenerArray.push(listenerFunc) }; window.celFinishHeaderHandler = function () { celOnFinishHeaderListenerArray.forEach(function (listener) { try { listener() } catch (exp) { console.error("Failed to execute celOnFinishHeader listener. ", exp) } }) }; if (typeof window.getCelDomain === "undefined") { window.getCelDomain = function () { const hostName = window.location.host; return hostName.replace(/^www\./, "") } } if (typeof window.CELEMENTS.LoadingIndicator === "undefined") { window.CELEMENTS.LoadingIndicator = Class.create({ _loadingImg: undefined, initialize: function () { const _me = this; _me._loadingImg = new Hash }, getLoadingIndicator: function (isSmallOrPxSize) { const _me = this; let loaderType = "ajax-loader-32px"; if (typeof isSmallOrPxSize === "boolean") { if (isSmallOrPxSize) { loaderType = "ajax-loader-16px" } } else if (typeof isSmallOrPxSize === "number") { loaderType = "ajax-loader-" + isSmallOrPxSize + "px" } if (!_me._loadingImg.get(loaderType)) { _me._loadingImg.set(loaderType, new Element("img", { src: CELEMENTS.getUtils().getPathPrefix() + "/file/resources/celRes/spinner/" + loaderType + ".png", class: "editorLoading", alt: "loading..." })) } return _me._loadingImg.get(loaderType).clone() } }) } if (typeof window.CELEMENTS.Utils === "undefined") { window.CELEMENTS.Utils = Class.create({ _srcOriginHost: undefined, getPathPrefix: function () { const _me = this; if (!_me._srcOriginHost) { let srcOriginHost = null; const scripts = document.getElementsByTagName("script"); let len = scripts.length; const re = new RegExp("(https?://[^/]*)/(([^/]*/)*)resources/celJS/initCelements(.min)?\\.js(\\?.*)?$"); let src; while (len--) { src = scripts[len].src; const srcMatches = src.match(re); if (src && srcMatches) { srcOriginHost = srcMatches[1]; const prefixPath = srcMatches[2]; const prefixPathSplit = prefixPath.split("/"); const prefixStr = prefixPathSplit.splice(0, prefixPathSplit.length - 2).join("/"); if (prefixStr != "") { srcOriginHost += "/" + prefixStr } break } } console.log("getPathPrefix computed prefixPath: ", srcOriginHost); _me._srcOriginHost = srcOriginHost } return _me._srcOriginHost }, convertFullNameToViewURL: function (fullName) { const _me = this; return _me.getPathPrefix() + ("/" + fullName.replace(/\./, "/")).replace(/\/Content\//, "/") } }); const globalUtilsInstance = new window.CELEMENTS.Utils; window.CELEMENTS.getUtils = function () { return globalUtilsInstance } } if (typeof window.CELEMENTS.getPathPrefix === "undefined") { window.CELEMENTS.getPathPrefix = function () { console.warn("deprecated call of window.CELEMENTS.getPathPrefix." + " Instead use window.CELEMENTS.getUtils().getPathPrefix()"); return window.CELEMENTS.getUtils().getPathPrefix() } } if (typeof window.getCelHost === "undefined") { window.getCelHost = function () { let celHost = document.location + "?"; if (document.location.pathname.indexOf("/skin/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/skin/resources/")) } else if (document.location.pathname.indexOf("/file/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/file/resources/")) } else { celHost = celHost.substring(0, celHost.indexOf("?")) } return celHost } } if (typeof window.CELEMENTS.Ajax === "undefined") { window.CELEMENTS.Ajax = {} } if (typeof window.CELEMENTS.Ajax.Reconnector === "undefined") { window.CELEMENTS.Ajax.Reconnector = Class.create({ _htmlElem: undefined, _callbackOnSuccess: undefined, _reconnectWait: undefined, _reconnectorHandlerBind: undefined, _cancelAjaxOnTimeoutBind: undefined, _reconnectorExecuter: undefined, _reconnectWaitStart: undefined, _minReconnectWait: undefined, _maxReconnectWait: undefined, _url: undefined, _configObj: undefined, initialize: function (htmlElemId, callbackOnSuccess, configObj) { const _me = this; _me._htmlElem = $(htmlElemId); _me._configObj = configObj || {}; _me._url = _me._configObj.url || window.getCelHost(); _me._callbackOnSuccess = callbackOnSuccess; _me._reconnectorHandlerBind = _me._reconnectorHandler.bind(_me); _me._cancelAjaxOnTimeoutBind = _me._cancelAjaxOnTimeout.bind(_me); _me._minReconnectWait = _me._configObj.minReconnectWait || 10; _me._maxReconnectWait = _me._configObj.maxReconnectWait || 30; _me._reset() }, _reset: function () { const _me = this; _me._reconnectWaitStart = _me._minReconnectWait }, setMinRecconectWait: function (minReconnectWait) { const _me = this; _me._minReconnectWait = minReconnectWait }, setMaxRecconectWait: function (maxReconnectWait) { const _me = this; _me._maxReconnectWait = maxReconnectWait }, _fireAjaxRecconectTrying: function () { const _me = this; return _me._htmlElem.fire("celements:AjaxReconnectTrying", _me._reconnectWait) }, _reconnectorHandler: function () { const _me = this; _me._reconnectWait--; if (_me._reconnectWait == 0) { _me._reconnectorExecuter.stop(); if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Trying..."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryNotice } _me._htmlElem.update(mesg) } _me._connectionTester() } else { if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Retrying in {} seconds."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryDelayNotice } mesg = mesg.replace("{}", _me._reconnectWait); _me._htmlElem.update(mesg); _me._htmlElem.fire("celements:AjaxReconnectFailed") } } }, start: function () { const _me = this; _me._reconnectWait = _me._reconnectWaitStart; _me._reconnectorExecuter = new PeriodicalExecuter(_me._reconnectorHandlerBind, 1) }, _cancelAjaxOnTimeout: function (ajaxCall) { if (!ajaxCall._complete) { ajaxCall.transport.abort() } }, _connectionTester: function () { const _me = this; const connectionTestAjax = new Ajax.Request(_me._url, { parameters: { ajax: 1, xpage: "celements_ajax", ajax_mode: "pageTypeWithLayout", overwriteLayout: "SimpleLayout" }, onSuccess: function () { _me._reset(); _me._reconnectorExecuter = null; _me._callbackOnSuccess(); _me._htmlElem.fire("celements:AjaxReconnectSuccess") }, onFailure: function () { _me._reconnectWaitStart = Math.min(_me._reconnectWaitStart * 2, _me._maxReconnectWait); _me.start() } }); _me._cancelAjaxOnTimeoutBind.delay(10, connectionTestAjax) } }) } window.CELEMENTS.UrlUtils = Class.create({ getParams: function (search) { const _me = this; search = search || window.location.search; const paramSplit = search.split(new RegExp("[?&]")); paramSplit.unshift(new Hash); return paramSplit.reduce(_me._splitUriSearch.bind(_me)) || new Hash }, joinParams: function (hash) { let paramsArray = []; $H(hash).each(function (pair) { const pairMapped = pair.value.map(function (elem) { return pair.key + "=" + encodeURI(elem) }); paramsArray = paramsArray.concat(pairMapped) }); return paramsArray.join("&") }, _splitUriSearch: function (paramHash, elem) { let key = elem.split("=", 1); if (key.length > 0 && key[0].length > 0) { key = key[0]; const val = decodeURI(elem.substring(key.length + 1)); if (!paramHash.get(key)) { paramHash.set(key, [val]) } else { paramHash.get(key).push(val) } } return paramHash } }); window.celMessages = {}; window.celMessages.isLoaded = false; try { new Ajax.Request(document.querySelector('meta[name="celements-messages-url"]').content, { method: "get", onSuccess: function (transport) { if (transport.responseText.isJSON()) { const newMessages = transport.responseText.evalJSON(); console.log("initCelements.js: finished getting dictionary messages."); newMessages.isLoaded = true; window.celMessages = newMessages; celMessagesCbFnArray.each(function (callbackFn) { try { callbackFn(newMessages) } catch (exp) { console.error("Failed to execute callbackFn!", exp) } }); $(document.body).fire("cel:messagesLoaded", newMessages) } else { console.error("noJSON!!! ", transport.responseText) } } }) } catch (exp) { console.error("Failed to get Cel-Messages async!", exp) } const celMessagesCbFnArray = []; window.celExecOnceAfterMessagesLoaded = function (callbackFn) { if (!celMessagesCbFnArray.includes(callbackFn)) { celMessagesCbFnArray.push(callbackFn); if (window.celMessages.isLoaded) { callbackFn(window.celMessages) } } }; if (typeof window.CELEMENTS.CssClassEventHandler === "undefined") { window.CELEMENTS.CssClassEventHandler = Class.create({ _htmlElement: undefined, _eventName: undefined, _cssSelector: undefined, _className: undefined, _actionFunction: undefined, _conditionFunction: undefined, _actionHandlerBind: undefined, initialize: function (htmlElement, eventName, cssSelector, className, actionFunction, condition) { const _me = this; _me._htmlElement = $(htmlElement); _me._eventName = eventName; _me._cssSelector = cssSelector; _me._className = className; _me._actionFunction = actionFunction; if (condition && !/\s|;/.test(condition)) { _me._conditionFunction = new Function("me", "origin", "return " + condition + ";") } _me._actionHandlerBind = _me._actionHandler.bind(_me); _me._registerActionHandler() }, _registerActionHandler: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); Event.observe(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - register: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) }, _actionHandler: function (event) { const _me = this; _me._getTargetElements().each(function (targetElement) { if (!_me._conditionFunction || _me._conditionFunction(targetElement, _me._htmlElement)) { _me._actionFunction(targetElement, _me._className); console.debug("EventHandler - upon", _me._eventName, "action [", _me._actionFunction.name, _me._className, "] executed on", targetElement) } else { console.debug("EventHandler - action skipped for failed condition [", _me._conditionFunction, "] on ", targetElement) } }) }, _getTargetElements: function () { const _me = this; if (_me._cssSelector.startsWith("^")) { parent = _me._htmlElement.up(_me._cssSelector.substring(1)); return parent ? [parent] : [] } else { return $$(_me._cssSelector) } }, unregister: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - unregister: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) } }) } if (typeof window.CELEMENTS.EventManager === "undefined") { window.CELEMENTS.EventManager = Class.create({ _instructionRegex: new RegExp(/([\w:]+)([%+-])([\w-]+):([^?]+)\??(.+)?/), _actionFunctionMap: { "+": Element.addClassName, "-": Element.removeClassName, "%": Element.toggleClassName }, _eventElements: undefined, _eventElemCounter: undefined, _interpretDataCelEventBind: undefined, _contentChangedHandlerBind: undefined, _intersectionObserver: undefined, _intersectionValues: [], initialize: function () { const _me = this; _me._eventElements = new Array; _me._eventElemCounter = 0; _me._interpretDataCelEventBind = _me._interpretDataCelEvent.bind(_me); _me._contentChangedHandlerBind = _me._contentChangedHandler.bind(_me); try { _me._intersectionObserver = new IntersectionObserver(function (entries) { entries.forEach(_me._handleIntersection.bind(_me)) }, { threshold: [0, .5, 1] }) } catch (exp) { console.warn("EventManager - initialize: IntersectionObserver not available", exp) } }, _splitDataCelEventList: function (dataValue) { let ret = new Array; if (dataValue) { ret = dataValue.replace(/([^&])&([^&])/g, "$1#SPLIT#$2").split("#SPLIT#") } return ret }, _parseEventInstruction: function (instruction) { const _me = this; const parts = instruction.match(_me._instructionRegex) || []; const data = { eventName: parts[1], action: parts[2], className: parts[3], cssSelector: parts[4], condition: parts[5] }; if (data.eventName && data.action && data.className && data.cssSelector) { return data } else { throw "parseEventInstruction: unable to parse event instruction '" + instruction + "'" } }, _createEventHandler: function (htmlElem, instruction) { const _me = this; const data = _me._parseEventInstruction(instruction); const actionFunction = _me._actionFunctionMap[data.action]; if (actionFunction) { if (_me._intersectionObserver && (data.eventName.startsWith("cel:enter") || data.eventName.startsWith("cel:leave"))) { _me._intersectionObserver.observe(htmlElem); console.debug("EventManager - observing intersection", htmlElem.dataset.celEventNb, data) } return new window.CELEMENTS.CssClassEventHandler(htmlElem, data.eventName, data.cssSelector, data.className, actionFunction, data.condition) } else { throw "createEventHandler: unknown action '" + data.action + '"' } }, _createEventElement: function (htmlElem) { const _me = this; const dataValue = htmlElem.dataset.celEvent; return { htmlElem: htmlElem, dataValue: dataValue, eventHandlers: _me._splitDataCelEventList(dataValue).map(function (instruction) { try { return _me._createEventHandler(htmlElem, instruction) } catch (exp) { console.error("EventManager - interpretData: invalid instruction ", exp, htmlElem) } }).filter(Boolean) } }, _interpretDataCelEvent: function (htmlElem) { const _me = this; const logPref = "EventManager - interpretData: "; if (htmlElem.classList.contains("celOnEventInit")) { console.debug(logPref, "skip already initialized: ", htmlElem) } else if (htmlElem.up(".cel_template")) { console.debug(logPref, "skip template element: ", htmlElem) } else { htmlElem.dataset.celEventNb = ++_me._eventElemCounter; const newElem = _me._createEventElement(htmlElem); if (newElem.eventHandlers.length > 0) { _me._eventElements.push(newElem) } else { console.warn(logPref, "no valid instructions found on ", htmlElem) } htmlElem.classList.add("celOnEventInit"); $(htmlElem).fire("celEM:init") } }, _handleIntersection: function (entry) { const _me = this; const htmlElem = entry.target; const eventNb = htmlElem.dataset.celEventNb; const previous = _me._intersectionValues[eventNb] || Object.freeze({ y: Number.MAX_SAFE_INTEGER, ratio: 0 }); const current = Object.freeze({ y: entry.boundingClientRect.y, ratio: entry.intersectionRatio }); const direction = current.y > previous.y ? "up" : "down"; const type = entry.isIntersecting && current.ratio >= previous.ratio ? "enter" : "leave"; const ratioA = type === "enter" ? current.ratio : previous.ratio; const ratioB = type === "leave" ? current.ratio : previous.ratio; const steps = []; if (ratioA >= 1 && ratioB < 1) steps.push(":full"); if (ratioA >= .5 && ratioB < .5) steps.push(":half"); if (ratioA > 0 && ratioB <= 0) steps.push(""); steps.forEach(function (step) { ["cel:" + type + step, "cel:" + type + step + ":" + direction].forEach(function (eventName) { console.debug("EventManager - intersect", eventName, "on", eventNb, previous, "->", current); htmlElem.fire(eventName) }) }); _me._intersectionValues[eventNb] = current }, _contentChangedHandler: function (event) { const _me = this; console.debug("EventManager - contentChanged ", event); if (event.memo && event.memo.htmlElem) { _me.updateCelEventHandlers(event.memo.htmlElem) } else { _me.updateCelEventHandlers() } }, updateCelEventHandlers: function (htmlContainer) { const _me = this; const rootElem = htmlContainer || document.body; Event.stopObserving($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); Event.observe($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); _me._removeDisappearedElems(); rootElem.querySelectorAll(".celOnEvent").forEach(_me._interpretDataCelEventBind) }, _removeDisappearedElems: function () { const _me = this; for (let i = _me._eventElements.length - 1; i >= 0; i--) { const elem = _me._eventElements[i]; const isInBody = $(document.body).contains(elem.htmlElem); const changedDataValue = elem.htmlElem.dataset.celEvent !== elem.dataValue; if (!isInBody || changedDataValue || !elem.htmlElem.classList.contains("celOnEventInit")) { elem.eventHandlers.forEach(function (handler) { handler.unregister() }); _me._eventElements.splice(i, 1); elem.htmlElem.classList.remove("celOnEventInit"); console.debug("EventManager - removeDisappearedElem: ", elem) } } } }); window.CELEMENTS.globalEventManager = new window.CELEMENTS.EventManager; document.addEventListener("DOMContentLoaded", window.CELEMENTS.globalEventManager._contentChangedHandlerBind) } const formValidations = new Hash; const registerValidation = function (formElem) { if (formElem && formElem.id) { const valid = new Validation(formElem, { immediate: true, useTitles: true, stopOnFirst: false }); formValidations.set(formElem.id, valid) } else { console.error("failed to register validation on form with no id. ", formElem) } }; document.addEventListener("DOMContentLoaded", function () { $$("form.cel_form_validation").each(registerValidation); $(document.body).observe("cel_yuiOverlay:contentChanged", function (event) { const containerElem = event.findElement(); if (containerElem) { containerElem.select("form.cel_form_validation").each(registerValidation) } }) }); window.celAddOnFinishHeaderListener(function () { const metas = $$('meta[name="cel-GAA-Num"]'); if (metas.size() > 0 && metas[0].content != "") { const gaaNum = metas[0].content; if (gaaNum.startsWith("UA-")) { (function (i, s, o, g, r, a, m) { i["GoogleAnalyticsObject"] = r; i[r] = i[r] || function () { (i[r].q = i[r].q || []).push(arguments) }, i[r].l = 1 * new Date; a = s.createElement(o), m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) })(window, document, "script", "//www.google-analytics.com/analytics.js", "ga"); ga("create", gaaNum, window.getCelDomain()); ga("set", "anonymizeIp", true); ga("send", "pageview"); console.log("finish initalizing google universal analytics.", gaaNum) } else { (function (d, o, g, s, m) { s = d.createElement(o); m = d.getElementsByTagName(o)[0]; s.async = 1; s.src = g; m.parentNode.insertBefore(s, m) })(document, "script", "https://www.googletagmanager.com/gtag/js?id=" + gaaNum); window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments) } gtag("js", new Date); gtag("config", gaaNum); console.log("finish initalizing google analytics v4.", gaaNum) } } }); document.addEventListener("DOMContentLoaded", function () { if (typeof $j("img[usemap]").rwdImageMaps !== "undefined") { $j("img[usemap]").rwdImageMaps() } }); document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.presentation && CELEMENTS.presentation.getOverlayObj && CELEMENTS.presentation.getOverlayObj()) { CELEMENTS.presentation.getOverlayObj({ overlayLayout: "SimpleLayout" }).registerOpenHandler() } }); let mobileDim = null; const cel_updateOrientationCSSclasses = function () { const innerWidth = mobileDim.getInnerWidth(); const innerHeight = mobileDim.getInnerHeight(); if (innerWidth > innerHeight) { $(document.body).removeClassName("cel_orientation_portrait"); $(document.body).addClassName("cel_orientation_landscape") } else { $(document.body).removeClassName("cel_orientation_landscape"); $(document.body).addClassName("cel_orientation_portrait") } }; document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.mobile && CELEMENTS.mobile.Dimensions) { mobileDim = new CELEMENTS.mobile.Dimensions; Event.stopObserving(window, "orientationchange", cel_updateOrientationCSSclasses); Event.observe(window, "orientationchange", cel_updateOrientationCSSclasses) } }); const cel_initAllMultiselect = function (event) { console.debug("initAllMultiselect"); if ($j().multiselect != undefined) { $j(".celBootstrap,.celMultiselect").filter(":visible,.celForceMultiselect").each(function (index, element) { if (!$(element).up(".cel_template")) { console.debug("initAllMultiselect: ", element); cel_initAllMultiselect_element(element) } }) } else { console.debug("initAllMultiselect: bootstrap multiselect undefined") } }; const cel_initAllMultiselect_element = function (element) { let params = { numberDisplayed: 3, onDropdownHidden: cel_initAllMultiselect_onDropdownHidden, onChange: cel_initAllMultiselect_onChange }; let bootstrapCfg = element.getAttribute("data-bootstrapConfig"); if (!bootstrapCfg && element.getAttribute("data-multiselectAttr")) { bootstrapCfg = element.getAttribute("data-multiselectAttr"); console.warn("initAllMultiselect: deprecated data-multiselectAttr in use", element) } if (bootstrapCfg) { params = $j.extend(params, JSON.parse(bootstrapCfg)) } const multiselect = $j(element).multiselect(params); $(document.body).fire("cel:multiselectInitialized", { multiselect: multiselect }) }; const cel_initAllMultiselect_onDropdownHidden = function (event) { $j(event.target).css("display", ""); event.target.fire("cel:multiselectOnDropdownHidden") }; const cel_initAllMultiselect_onChange = function (option, checked, select) { const multiselectElement = this; console.debug("fire cel:multiselectOnChange on: ", multiselectElement); $(option[0]).fire("cel:multiselectOnChange", { multiselect: multiselectElement, checked: checked, select: select }) }; const cel_initAllMultiselect_tabMenuPanel = function (event) { $("tabMenuPanel").select(".celBootstrap,.celMultiselect").each(function (element) { if (element.visible()) { element.addClassName("celForceMultiselect") } }); cel_initAllMultiselect(event) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initMultiselect", cel_initAllMultiselect); $(document.body).stopObserving("celements:contentChanged", cel_initAllMultiselect); $(document.body).observe("cel:initMultiselect", cel_initAllMultiselect); $(document.body).observe("celements:contentChanged", cel_initAllMultiselect); if ($("tabMenuPanel")) { $("tabMenuPanel").stopObserving("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel); $("tabMenuPanel").observe("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel) } $(document.body).fire("cel:initMultiselect") }); const cel_addMaxDimToFluidImg = function (event) { $$("img.cel_fluidresizeWidth").each(function (imgElem) { imgElem.setStyle({ maxWidth: imgElem.readAttribute("width") + "px" }) }); $$("img.cel_fluidresizeHeight").each(function (imgElem) { imgElem.setStyle({ maxHeight: imgElem.readAttribute("height") + "px" }) }) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).stopObserving("celements:contentChanged", cel_addMaxDimToFluidImg); $(document.body).observe("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).observe("celements:contentChanged", cel_addMaxDimToFluidImg) }); document.addEventListener("DOMContentLoaded", function () { $$(".generalOverlayWrapper .generalOverlay .exitOnClose").each(function (elem) { elem.stopObserving("click", cel_closeOverlayWindow); elem.observe("click", cel_closeOverlayWindow) }) }); const cel_closeOverlayWindow = function (event) { event.stop(); window.close() }; const updateCelMessages = function () { if (typeof $j.format !== "undefined") { $j.format.locale({ date: celMessages.jqueryFormater }) } }; document.addEventListener("DOMContentLoaded", function () { if (window.celMessages.isLoaded && typeof celMessages.jqueryFormater === "object") { updateCelMessages() } else { $(document.body).observe("cel:messagesLoaded", updateCelMessages) } }) })(window); diff --git a/celements-webapp/src/main/webapp/resources/celJS/validation.js b/celements-webapp/src/main/webapp/resources/celJS/validation.js index 802ea9d0b..7fa587cee 100644 --- a/celements-webapp/src/main/webapp/resources/celJS/validation.js +++ b/celements-webapp/src/main/webapp/resources/celJS/validation.js @@ -539,12 +539,8 @@ ['validate-docname', null, Validator.methods.validDocName], ]; - new Ajax.Request(getCelHost(), { - method: 'post', - parameters: { - xpage: 'celements_ajax', - ajax_mode: 'ValidationMessages', - }, + new Ajax.Request(document.querySelector('meta[name="celements-validation-messages-url"]').content, { + method: 'get', onSuccess: function (transport) { if (transport.responseText.isJSON()) { Validation.messages = Validation.messages.merge(transport.responseText.evalJSON()); diff --git a/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm b/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm index c0c385bc4..b8b2b92fa 100644 --- a/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm +++ b/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm @@ -2,6 +2,7 @@ + #set($jsService = $services.javascript) #set($extJsParamSync = $!jsService.createExtJSParam().setAction('file')) diff --git a/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm b/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm index 487f756fe..a0e8be53e 100644 --- a/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm +++ b/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm @@ -29,5 +29,7 @@ #end #if($!withoutDefaultHeaders == false) + + #template("celMacros/includeDefaultHeader.vm") #end diff --git a/celements-webapp/src/main/webapp/templates/htmlheader.vm b/celements-webapp/src/main/webapp/templates/htmlheader.vm index 3c18efdcd..9a87dcbad 100644 --- a/celements-webapp/src/main/webapp/templates/htmlheader.vm +++ b/celements-webapp/src/main/webapp/templates/htmlheader.vm @@ -68,6 +68,8 @@ + + ## --------------------------------------------------------------------------------------------------------------- ## Localize GWT applications. ## --------------------------------------------------------------------------------------------------------------- diff --git a/component/pom.xml b/component/pom.xml new file mode 100644 index 000000000..c242eb4dd --- /dev/null +++ b/component/pom.xml @@ -0,0 +1,80 @@ + + + + com.celements + celements-parent + 7.1-SNAPSHOT + + 4.0.0 + https://github.com/celements/celements-web + celements-web-component + 7.1-SNAPSHOT + Celements Web Component + + + com.celements + celements-model + provided + + + com.celements + celements-spring-security + provided + + + com.celements + celements-xwiki-core + provided + + + com.celements + celements-observation + provided + + + com.celements + celements-xwiki-velocity + provided + + + com.celements + celements-core + provided + + + org.springframework + spring-context + provided + + + org.springframework + spring-web + provided + + + org.springframework + spring-webmvc + provided + + + javax.inject + javax.inject + + + javax.servlet + javax.servlet-api + provided + + + com.celements + celements-shared-tests + test + + + + scm:git:git://github.com/celements/celements-web + scm:git:git@github.com:celements/celements-web.git + https://github.com/celements/celements-web + HEAD + + diff --git a/component/src/main/java/com/celements/web/api/MessagesController.java b/component/src/main/java/com/celements/web/api/MessagesController.java new file mode 100644 index 000000000..115ec2909 --- /dev/null +++ b/component/src/main/java/com/celements/web/api/MessagesController.java @@ -0,0 +1,70 @@ +package com.celements.web.api; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; + +import javax.inject.Inject; +import javax.servlet.ServletContext; + +import org.apache.velocity.VelocityContext; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.xwiki.velocity.VelocityManager; +import org.xwiki.velocity.XWikiVelocityException; + +import com.celements.spring.security.AuthenticatedBaseController; +import com.celements.web.service.IPrepareVelocityContext; + +@RestController +@RequestMapping("/v1/messages") +@PreAuthorize("permitAll()") +public class MessagesController extends AuthenticatedBaseController { + + private final ServletContext servletContext; + + private final VelocityManager velocityManager; + + private final IPrepareVelocityContext prepareVelocityContext; + + @Inject + public MessagesController(ServletContext servletContext, VelocityManager velocityManager, + IPrepareVelocityContext prepareVelocityContext) { + this.servletContext = servletContext; + this.velocityManager = velocityManager; + this.prepareVelocityContext = prepareVelocityContext; + } + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8") + public String getMessages() throws IOException, XWikiVelocityException { + return renderTemplate("/templates/celAjax/Messages.vm"); + } + + @GetMapping(value = "/validation", produces = MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8") + public String getValidationMessages() throws IOException, XWikiVelocityException { + return renderTemplate("/templates/celAjax/ValidationMessages.vm"); + } + + private String renderTemplate(String template) throws IOException, XWikiVelocityException { + checkAuth(); + VelocityContext velocityContext = velocityManager.getVelocityContext(); + prepareVelocityContext.prepareVelocityContext(velocityContext); + var writer = new StringWriter(); + velocityManager.getVelocityEngine().evaluate(velocityContext, writer, template, + getTemplateContent(template)); + return writer.toString().trim(); + } + + private String getTemplateContent(String template) throws IOException { + try (InputStream stream = servletContext.getResourceAsStream(template)) { + if (stream == null) { + throw new IOException("Template not found: " + template); + } + return new String(stream.readAllBytes(), StandardCharsets.UTF_8); + } + } +} diff --git a/component/src/test/java/com/celements/web/api/MessagesControllerTest.java b/component/src/test/java/com/celements/web/api/MessagesControllerTest.java new file mode 100644 index 000000000..66fc43ac0 --- /dev/null +++ b/component/src/test/java/com/celements/web/api/MessagesControllerTest.java @@ -0,0 +1,97 @@ +package com.celements.web.api; + +import static org.easymock.EasyMock.*; +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +import javax.servlet.ServletContext; + +import org.apache.velocity.VelocityContext; +import org.junit.Before; +import org.junit.Test; +import org.xwiki.velocity.VelocityEngine; +import org.xwiki.velocity.VelocityManager; + +import com.celements.auth.user.User; +import com.celements.web.service.IPrepareVelocityContext; + +public class MessagesControllerTest { + + private ServletContext servletContext; + + private VelocityManager velocityManager; + + private IPrepareVelocityContext prepareVelocityContext; + + private MessagesController controller; + + @Before + public void prepareTest() { + servletContext = createMock(ServletContext.class); + velocityManager = createMock(VelocityManager.class); + prepareVelocityContext = createMock(IPrepareVelocityContext.class); + controller = new TestMessagesController(servletContext, velocityManager, prepareVelocityContext); + } + + @Test + public void test_getMessages_rendersGeneralTemplateWithRequestVelocityContext() throws Exception { + var velocityEngine = expectTemplateRendering("/templates/celAjax/Messages.vm", + " {\"message\":true} "); + replay(servletContext, velocityManager, prepareVelocityContext, velocityEngine); + assertEquals("{\"message\":true}", controller.getMessages()); + assertTrue(((TestMessagesController) controller).isCheckAuthCalled()); + verify(servletContext, velocityManager, prepareVelocityContext, velocityEngine); + } + + @Test + public void test_getValidationMessages_rendersValidationTemplateWithRequestVelocityContext() + throws Exception { + var velocityEngine = expectTemplateRendering("/templates/celAjax/ValidationMessages.vm", + " {\"required\":true} "); + replay(servletContext, velocityManager, prepareVelocityContext, velocityEngine); + assertEquals("{\"required\":true}", controller.getValidationMessages()); + assertTrue(((TestMessagesController) controller).isCheckAuthCalled()); + verify(servletContext, velocityManager, prepareVelocityContext, velocityEngine); + } + + private VelocityEngine expectTemplateRendering(String template, String renderedTemplate) + throws Exception { + var velocityContext = new VelocityContext(); + VelocityEngine velocityEngine = createMock(VelocityEngine.class); + expect(velocityManager.getVelocityContext()).andReturn(velocityContext); + prepareVelocityContext.prepareVelocityContext(velocityContext); + expect(velocityManager.getVelocityEngine()).andReturn(velocityEngine); + expect(servletContext.getResourceAsStream(template)).andReturn( + new ByteArrayInputStream("template".getBytes(StandardCharsets.UTF_8))); + expect(velocityEngine.evaluate(same(velocityContext), isA(StringWriter.class), eq(template), + eq("template"))).andAnswer(() -> { + ((StringWriter) getCurrentArguments()[1]).write(renderedTemplate); + return true; + }); + return velocityEngine; + } + + private static final class TestMessagesController extends MessagesController { + + private boolean checkAuthCalled; + + TestMessagesController(ServletContext servletContext, VelocityManager velocityManager, + IPrepareVelocityContext prepareVelocityContext) { + super(servletContext, velocityManager, prepareVelocityContext); + } + + @Override + protected Optional checkAuth() { + checkAuthCalled = true; + return Optional.empty(); + } + + boolean isCheckAuthCalled() { + return checkAuthCalled; + } + } +} From ba7099c66c72044591e6b5255a6414e52090c7dd Mon Sep 17 00:00:00 2001 From: Fabian Pichler Date: Sun, 2 Aug 2026 06:16:34 +0200 Subject: [PATCH 2/2] CELDEV-1332 consume messages overlay --- celements-webapp/Jenkinsfile.release | 3 +- celements-webapp/pom.xml | 3 +- .../webapp/resources/celJS/initCelements.js | 2 +- .../resources/celJS/initCelements.min.js | 2 +- .../main/webapp/resources/celJS/validation.js | 2 +- .../templates/celAjax/FlowplayerInOverlay.vm | 1 - .../main/webapp/templates/celAjax/Messages.vm | 5 - .../templates/celAjax/ValidationMessages.vm | 5 - .../webapp/templates/celMacros/CelMessages.vm | 215 ------------------ .../celMacros/CelValidationMessages.vm | 19 -- .../celMacros/startCelementsDocument.vm | 2 - .../src/main/webapp/templates/htmlheader.vm | 2 - component/pom.xml | 80 ------- .../celements/web/api/MessagesController.java | 70 ------ .../web/api/MessagesControllerTest.java | 97 -------- 15 files changed, 7 insertions(+), 501 deletions(-) delete mode 100644 celements-webapp/src/main/webapp/templates/celAjax/Messages.vm delete mode 100644 celements-webapp/src/main/webapp/templates/celAjax/ValidationMessages.vm delete mode 100644 celements-webapp/src/main/webapp/templates/celMacros/CelMessages.vm delete mode 100644 celements-webapp/src/main/webapp/templates/celMacros/CelValidationMessages.vm delete mode 100644 component/pom.xml delete mode 100644 component/src/main/java/com/celements/web/api/MessagesController.java delete mode 100644 component/src/test/java/com/celements/web/api/MessagesControllerTest.java diff --git a/celements-webapp/Jenkinsfile.release b/celements-webapp/Jenkinsfile.release index 6ee2a72fa..1256aa2c6 100644 --- a/celements-webapp/Jenkinsfile.release +++ b/celements-webapp/Jenkinsfile.release @@ -67,7 +67,8 @@ releasePipeline(manifest: [ 'celements-rte-tiny6-war', 'celements-rte-langs-tiny4-war', 'celements-rte-langs-tiny6-war', - 'celements-web-component-jar', + 'celements-messages-jar', + 'celements-messages-web', 'celements-webapp-war', ], ]) diff --git a/celements-webapp/pom.xml b/celements-webapp/pom.xml index a4302ff84..f15411790 100644 --- a/celements-webapp/pom.xml +++ b/celements-webapp/pom.xml @@ -246,7 +246,8 @@ com.celements - celements-web-component + celements-messages-web + war com.celements diff --git a/celements-webapp/src/main/webapp/resources/celJS/initCelements.js b/celements-webapp/src/main/webapp/resources/celJS/initCelements.js index 499ad4c70..fbc48e853 100644 --- a/celements-webapp/src/main/webapp/resources/celJS/initCelements.js +++ b/celements-webapp/src/main/webapp/resources/celJS/initCelements.js @@ -484,7 +484,7 @@ window.celMessages.isLoaded = false; try { - new Ajax.Request(document.querySelector('meta[name="celements-messages-url"]').content, { + new Ajax.Request('/api/v1/messages', { method: 'get', onSuccess: function (transport) { if (transport.responseText.isJSON()) { diff --git a/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js b/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js index c44e643cc..ac8895f22 100644 --- a/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js +++ b/celements-webapp/src/main/webapp/resources/celJS/initCelements.min.js @@ -1 +1 @@ -(function (window, undefined) { "use strict"; if (typeof window.console === "undefined") { window.console = {} } if (typeof window.console.error === "undefined") { window.console.error = Prototype.emptyFunction } if (typeof window.console.warn === "undefined") { window.console.warn = window.console.error } if (typeof window.console.info === "undefined") { window.console.info = window.console.warn } if (typeof window.console.log === "undefined") { window.console.log = window.console.info } if (typeof window.console.debug === "undefined") { window.console.debug = window.console.log } if (typeof window.CELEMENTS === "undefined") { window.CELEMENTS = {} } if (typeof window.CELEMENTS.mixins === "undefined") { window.CELEMENTS.mixins = {} } if (typeof window.CELEMENTS.mixins.Event === "undefined") { window.CELEMENTS.mixins.Event = Class.create({ memo: undefined, stopped: undefined, eventName: undefined, type: undefined, detail: undefined, cancelable: undefined, defaultPrevented: undefined, target: undefined, initialize: function (eventName, memo, target) { this.memo = memo; this.eventName = eventName; this.stopped = false; this.type = eventName; this.detail = memo; this.cancelable = true; this.defaultPrevented = false; this.target = target || (memo ? memo.target : null) }, stop: function () { if (this.cancelable) { this.stopped = true; this.defaultPrevented = true } }, preventDefault: function () { this.stop() }, findElement: function () { return this.target } }) } if (typeof window.CELEMENTS.mixins.Observable === "undefined") { window.CELEMENTS.mixins.Observable = { _celEventMap: null, _getCelEventMap: function (eventKey) { if (!this._celEventMap) { this._celEventMap = new Map } if (eventKey) { if (!this._celEventMap.has(eventKey)) { this._celEventMap.set(eventKey, []) } return this._celEventMap.get(eventKey) } return this._celEventMap }, celObserve: function (eventKey, callbackFN) { console.debug("cel celObserve:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celObserve call" } this._getCelEventMap(eventKey).push(callbackFN) }, celStopObserving: function (eventKey, callbackFN) { console.debug("cel celStopObserving:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celStopObserving call" } this._getCelEventMap().set(eventKey, this._getCelEventMap(eventKey).filter(function (fn) { return fn !== callbackFN })) }, celFire: function (eventKey, memo) { if (!eventKey) { throw "undefined eventKey in celFire call" } const event = new CELEMENTS.mixins.Event(eventKey, memo, this); const listeners = this._getCelEventMap(eventKey); console.debug("cel celFire:", event, "on", listeners); listeners.forEach(function (callbackFN) { try { callbackFN(event) } catch (exp) { console.error("listener in celFire failed for event", eventKey, callbackFN, exp) } }); return event } } } let celOnBeforeLoadListenerArray = []; window.celAddOnBeforeLoadListener = function (listenerFunc) { console.warn("celAddOnBeforeLoad is deprecated since open-celements 5.4 / January 2022." + ' Instead register a listener on "DOMContentLoaded"', listenerFunc); celOnBeforeLoadListenerArray.push(listenerFunc) }; document.addEventListener("DOMContentLoaded", function () { celOnBeforeLoadListenerArray.forEach(function (listener) { try { listener() } catch (e) { console.error("Listener for celOnBeforeLoad failed: ", e) } }); $(document.body).fire("celements:beforeOnLoad") }); let celOnFinishHeaderListenerArray = []; window.celAddOnFinishHeaderListener = function (listenerFunc) { celOnFinishHeaderListenerArray.push(listenerFunc) }; window.celFinishHeaderHandler = function () { celOnFinishHeaderListenerArray.forEach(function (listener) { try { listener() } catch (exp) { console.error("Failed to execute celOnFinishHeader listener. ", exp) } }) }; if (typeof window.getCelDomain === "undefined") { window.getCelDomain = function () { const hostName = window.location.host; return hostName.replace(/^www\./, "") } } if (typeof window.CELEMENTS.LoadingIndicator === "undefined") { window.CELEMENTS.LoadingIndicator = Class.create({ _loadingImg: undefined, initialize: function () { const _me = this; _me._loadingImg = new Hash }, getLoadingIndicator: function (isSmallOrPxSize) { const _me = this; let loaderType = "ajax-loader-32px"; if (typeof isSmallOrPxSize === "boolean") { if (isSmallOrPxSize) { loaderType = "ajax-loader-16px" } } else if (typeof isSmallOrPxSize === "number") { loaderType = "ajax-loader-" + isSmallOrPxSize + "px" } if (!_me._loadingImg.get(loaderType)) { _me._loadingImg.set(loaderType, new Element("img", { src: CELEMENTS.getUtils().getPathPrefix() + "/file/resources/celRes/spinner/" + loaderType + ".png", class: "editorLoading", alt: "loading..." })) } return _me._loadingImg.get(loaderType).clone() } }) } if (typeof window.CELEMENTS.Utils === "undefined") { window.CELEMENTS.Utils = Class.create({ _srcOriginHost: undefined, getPathPrefix: function () { const _me = this; if (!_me._srcOriginHost) { let srcOriginHost = null; const scripts = document.getElementsByTagName("script"); let len = scripts.length; const re = new RegExp("(https?://[^/]*)/(([^/]*/)*)resources/celJS/initCelements(.min)?\\.js(\\?.*)?$"); let src; while (len--) { src = scripts[len].src; const srcMatches = src.match(re); if (src && srcMatches) { srcOriginHost = srcMatches[1]; const prefixPath = srcMatches[2]; const prefixPathSplit = prefixPath.split("/"); const prefixStr = prefixPathSplit.splice(0, prefixPathSplit.length - 2).join("/"); if (prefixStr != "") { srcOriginHost += "/" + prefixStr } break } } console.log("getPathPrefix computed prefixPath: ", srcOriginHost); _me._srcOriginHost = srcOriginHost } return _me._srcOriginHost }, convertFullNameToViewURL: function (fullName) { const _me = this; return _me.getPathPrefix() + ("/" + fullName.replace(/\./, "/")).replace(/\/Content\//, "/") } }); const globalUtilsInstance = new window.CELEMENTS.Utils; window.CELEMENTS.getUtils = function () { return globalUtilsInstance } } if (typeof window.CELEMENTS.getPathPrefix === "undefined") { window.CELEMENTS.getPathPrefix = function () { console.warn("deprecated call of window.CELEMENTS.getPathPrefix." + " Instead use window.CELEMENTS.getUtils().getPathPrefix()"); return window.CELEMENTS.getUtils().getPathPrefix() } } if (typeof window.getCelHost === "undefined") { window.getCelHost = function () { let celHost = document.location + "?"; if (document.location.pathname.indexOf("/skin/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/skin/resources/")) } else if (document.location.pathname.indexOf("/file/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/file/resources/")) } else { celHost = celHost.substring(0, celHost.indexOf("?")) } return celHost } } if (typeof window.CELEMENTS.Ajax === "undefined") { window.CELEMENTS.Ajax = {} } if (typeof window.CELEMENTS.Ajax.Reconnector === "undefined") { window.CELEMENTS.Ajax.Reconnector = Class.create({ _htmlElem: undefined, _callbackOnSuccess: undefined, _reconnectWait: undefined, _reconnectorHandlerBind: undefined, _cancelAjaxOnTimeoutBind: undefined, _reconnectorExecuter: undefined, _reconnectWaitStart: undefined, _minReconnectWait: undefined, _maxReconnectWait: undefined, _url: undefined, _configObj: undefined, initialize: function (htmlElemId, callbackOnSuccess, configObj) { const _me = this; _me._htmlElem = $(htmlElemId); _me._configObj = configObj || {}; _me._url = _me._configObj.url || window.getCelHost(); _me._callbackOnSuccess = callbackOnSuccess; _me._reconnectorHandlerBind = _me._reconnectorHandler.bind(_me); _me._cancelAjaxOnTimeoutBind = _me._cancelAjaxOnTimeout.bind(_me); _me._minReconnectWait = _me._configObj.minReconnectWait || 10; _me._maxReconnectWait = _me._configObj.maxReconnectWait || 30; _me._reset() }, _reset: function () { const _me = this; _me._reconnectWaitStart = _me._minReconnectWait }, setMinRecconectWait: function (minReconnectWait) { const _me = this; _me._minReconnectWait = minReconnectWait }, setMaxRecconectWait: function (maxReconnectWait) { const _me = this; _me._maxReconnectWait = maxReconnectWait }, _fireAjaxRecconectTrying: function () { const _me = this; return _me._htmlElem.fire("celements:AjaxReconnectTrying", _me._reconnectWait) }, _reconnectorHandler: function () { const _me = this; _me._reconnectWait--; if (_me._reconnectWait == 0) { _me._reconnectorExecuter.stop(); if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Trying..."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryNotice } _me._htmlElem.update(mesg) } _me._connectionTester() } else { if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Retrying in {} seconds."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryDelayNotice } mesg = mesg.replace("{}", _me._reconnectWait); _me._htmlElem.update(mesg); _me._htmlElem.fire("celements:AjaxReconnectFailed") } } }, start: function () { const _me = this; _me._reconnectWait = _me._reconnectWaitStart; _me._reconnectorExecuter = new PeriodicalExecuter(_me._reconnectorHandlerBind, 1) }, _cancelAjaxOnTimeout: function (ajaxCall) { if (!ajaxCall._complete) { ajaxCall.transport.abort() } }, _connectionTester: function () { const _me = this; const connectionTestAjax = new Ajax.Request(_me._url, { parameters: { ajax: 1, xpage: "celements_ajax", ajax_mode: "pageTypeWithLayout", overwriteLayout: "SimpleLayout" }, onSuccess: function () { _me._reset(); _me._reconnectorExecuter = null; _me._callbackOnSuccess(); _me._htmlElem.fire("celements:AjaxReconnectSuccess") }, onFailure: function () { _me._reconnectWaitStart = Math.min(_me._reconnectWaitStart * 2, _me._maxReconnectWait); _me.start() } }); _me._cancelAjaxOnTimeoutBind.delay(10, connectionTestAjax) } }) } window.CELEMENTS.UrlUtils = Class.create({ getParams: function (search) { const _me = this; search = search || window.location.search; const paramSplit = search.split(new RegExp("[?&]")); paramSplit.unshift(new Hash); return paramSplit.reduce(_me._splitUriSearch.bind(_me)) || new Hash }, joinParams: function (hash) { let paramsArray = []; $H(hash).each(function (pair) { const pairMapped = pair.value.map(function (elem) { return pair.key + "=" + encodeURI(elem) }); paramsArray = paramsArray.concat(pairMapped) }); return paramsArray.join("&") }, _splitUriSearch: function (paramHash, elem) { let key = elem.split("=", 1); if (key.length > 0 && key[0].length > 0) { key = key[0]; const val = decodeURI(elem.substring(key.length + 1)); if (!paramHash.get(key)) { paramHash.set(key, [val]) } else { paramHash.get(key).push(val) } } return paramHash } }); window.celMessages = {}; window.celMessages.isLoaded = false; try { new Ajax.Request(document.querySelector('meta[name="celements-messages-url"]').content, { method: "get", onSuccess: function (transport) { if (transport.responseText.isJSON()) { const newMessages = transport.responseText.evalJSON(); console.log("initCelements.js: finished getting dictionary messages."); newMessages.isLoaded = true; window.celMessages = newMessages; celMessagesCbFnArray.each(function (callbackFn) { try { callbackFn(newMessages) } catch (exp) { console.error("Failed to execute callbackFn!", exp) } }); $(document.body).fire("cel:messagesLoaded", newMessages) } else { console.error("noJSON!!! ", transport.responseText) } } }) } catch (exp) { console.error("Failed to get Cel-Messages async!", exp) } const celMessagesCbFnArray = []; window.celExecOnceAfterMessagesLoaded = function (callbackFn) { if (!celMessagesCbFnArray.includes(callbackFn)) { celMessagesCbFnArray.push(callbackFn); if (window.celMessages.isLoaded) { callbackFn(window.celMessages) } } }; if (typeof window.CELEMENTS.CssClassEventHandler === "undefined") { window.CELEMENTS.CssClassEventHandler = Class.create({ _htmlElement: undefined, _eventName: undefined, _cssSelector: undefined, _className: undefined, _actionFunction: undefined, _conditionFunction: undefined, _actionHandlerBind: undefined, initialize: function (htmlElement, eventName, cssSelector, className, actionFunction, condition) { const _me = this; _me._htmlElement = $(htmlElement); _me._eventName = eventName; _me._cssSelector = cssSelector; _me._className = className; _me._actionFunction = actionFunction; if (condition && !/\s|;/.test(condition)) { _me._conditionFunction = new Function("me", "origin", "return " + condition + ";") } _me._actionHandlerBind = _me._actionHandler.bind(_me); _me._registerActionHandler() }, _registerActionHandler: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); Event.observe(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - register: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) }, _actionHandler: function (event) { const _me = this; _me._getTargetElements().each(function (targetElement) { if (!_me._conditionFunction || _me._conditionFunction(targetElement, _me._htmlElement)) { _me._actionFunction(targetElement, _me._className); console.debug("EventHandler - upon", _me._eventName, "action [", _me._actionFunction.name, _me._className, "] executed on", targetElement) } else { console.debug("EventHandler - action skipped for failed condition [", _me._conditionFunction, "] on ", targetElement) } }) }, _getTargetElements: function () { const _me = this; if (_me._cssSelector.startsWith("^")) { parent = _me._htmlElement.up(_me._cssSelector.substring(1)); return parent ? [parent] : [] } else { return $$(_me._cssSelector) } }, unregister: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - unregister: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) } }) } if (typeof window.CELEMENTS.EventManager === "undefined") { window.CELEMENTS.EventManager = Class.create({ _instructionRegex: new RegExp(/([\w:]+)([%+-])([\w-]+):([^?]+)\??(.+)?/), _actionFunctionMap: { "+": Element.addClassName, "-": Element.removeClassName, "%": Element.toggleClassName }, _eventElements: undefined, _eventElemCounter: undefined, _interpretDataCelEventBind: undefined, _contentChangedHandlerBind: undefined, _intersectionObserver: undefined, _intersectionValues: [], initialize: function () { const _me = this; _me._eventElements = new Array; _me._eventElemCounter = 0; _me._interpretDataCelEventBind = _me._interpretDataCelEvent.bind(_me); _me._contentChangedHandlerBind = _me._contentChangedHandler.bind(_me); try { _me._intersectionObserver = new IntersectionObserver(function (entries) { entries.forEach(_me._handleIntersection.bind(_me)) }, { threshold: [0, .5, 1] }) } catch (exp) { console.warn("EventManager - initialize: IntersectionObserver not available", exp) } }, _splitDataCelEventList: function (dataValue) { let ret = new Array; if (dataValue) { ret = dataValue.replace(/([^&])&([^&])/g, "$1#SPLIT#$2").split("#SPLIT#") } return ret }, _parseEventInstruction: function (instruction) { const _me = this; const parts = instruction.match(_me._instructionRegex) || []; const data = { eventName: parts[1], action: parts[2], className: parts[3], cssSelector: parts[4], condition: parts[5] }; if (data.eventName && data.action && data.className && data.cssSelector) { return data } else { throw "parseEventInstruction: unable to parse event instruction '" + instruction + "'" } }, _createEventHandler: function (htmlElem, instruction) { const _me = this; const data = _me._parseEventInstruction(instruction); const actionFunction = _me._actionFunctionMap[data.action]; if (actionFunction) { if (_me._intersectionObserver && (data.eventName.startsWith("cel:enter") || data.eventName.startsWith("cel:leave"))) { _me._intersectionObserver.observe(htmlElem); console.debug("EventManager - observing intersection", htmlElem.dataset.celEventNb, data) } return new window.CELEMENTS.CssClassEventHandler(htmlElem, data.eventName, data.cssSelector, data.className, actionFunction, data.condition) } else { throw "createEventHandler: unknown action '" + data.action + '"' } }, _createEventElement: function (htmlElem) { const _me = this; const dataValue = htmlElem.dataset.celEvent; return { htmlElem: htmlElem, dataValue: dataValue, eventHandlers: _me._splitDataCelEventList(dataValue).map(function (instruction) { try { return _me._createEventHandler(htmlElem, instruction) } catch (exp) { console.error("EventManager - interpretData: invalid instruction ", exp, htmlElem) } }).filter(Boolean) } }, _interpretDataCelEvent: function (htmlElem) { const _me = this; const logPref = "EventManager - interpretData: "; if (htmlElem.classList.contains("celOnEventInit")) { console.debug(logPref, "skip already initialized: ", htmlElem) } else if (htmlElem.up(".cel_template")) { console.debug(logPref, "skip template element: ", htmlElem) } else { htmlElem.dataset.celEventNb = ++_me._eventElemCounter; const newElem = _me._createEventElement(htmlElem); if (newElem.eventHandlers.length > 0) { _me._eventElements.push(newElem) } else { console.warn(logPref, "no valid instructions found on ", htmlElem) } htmlElem.classList.add("celOnEventInit"); $(htmlElem).fire("celEM:init") } }, _handleIntersection: function (entry) { const _me = this; const htmlElem = entry.target; const eventNb = htmlElem.dataset.celEventNb; const previous = _me._intersectionValues[eventNb] || Object.freeze({ y: Number.MAX_SAFE_INTEGER, ratio: 0 }); const current = Object.freeze({ y: entry.boundingClientRect.y, ratio: entry.intersectionRatio }); const direction = current.y > previous.y ? "up" : "down"; const type = entry.isIntersecting && current.ratio >= previous.ratio ? "enter" : "leave"; const ratioA = type === "enter" ? current.ratio : previous.ratio; const ratioB = type === "leave" ? current.ratio : previous.ratio; const steps = []; if (ratioA >= 1 && ratioB < 1) steps.push(":full"); if (ratioA >= .5 && ratioB < .5) steps.push(":half"); if (ratioA > 0 && ratioB <= 0) steps.push(""); steps.forEach(function (step) { ["cel:" + type + step, "cel:" + type + step + ":" + direction].forEach(function (eventName) { console.debug("EventManager - intersect", eventName, "on", eventNb, previous, "->", current); htmlElem.fire(eventName) }) }); _me._intersectionValues[eventNb] = current }, _contentChangedHandler: function (event) { const _me = this; console.debug("EventManager - contentChanged ", event); if (event.memo && event.memo.htmlElem) { _me.updateCelEventHandlers(event.memo.htmlElem) } else { _me.updateCelEventHandlers() } }, updateCelEventHandlers: function (htmlContainer) { const _me = this; const rootElem = htmlContainer || document.body; Event.stopObserving($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); Event.observe($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); _me._removeDisappearedElems(); rootElem.querySelectorAll(".celOnEvent").forEach(_me._interpretDataCelEventBind) }, _removeDisappearedElems: function () { const _me = this; for (let i = _me._eventElements.length - 1; i >= 0; i--) { const elem = _me._eventElements[i]; const isInBody = $(document.body).contains(elem.htmlElem); const changedDataValue = elem.htmlElem.dataset.celEvent !== elem.dataValue; if (!isInBody || changedDataValue || !elem.htmlElem.classList.contains("celOnEventInit")) { elem.eventHandlers.forEach(function (handler) { handler.unregister() }); _me._eventElements.splice(i, 1); elem.htmlElem.classList.remove("celOnEventInit"); console.debug("EventManager - removeDisappearedElem: ", elem) } } } }); window.CELEMENTS.globalEventManager = new window.CELEMENTS.EventManager; document.addEventListener("DOMContentLoaded", window.CELEMENTS.globalEventManager._contentChangedHandlerBind) } const formValidations = new Hash; const registerValidation = function (formElem) { if (formElem && formElem.id) { const valid = new Validation(formElem, { immediate: true, useTitles: true, stopOnFirst: false }); formValidations.set(formElem.id, valid) } else { console.error("failed to register validation on form with no id. ", formElem) } }; document.addEventListener("DOMContentLoaded", function () { $$("form.cel_form_validation").each(registerValidation); $(document.body).observe("cel_yuiOverlay:contentChanged", function (event) { const containerElem = event.findElement(); if (containerElem) { containerElem.select("form.cel_form_validation").each(registerValidation) } }) }); window.celAddOnFinishHeaderListener(function () { const metas = $$('meta[name="cel-GAA-Num"]'); if (metas.size() > 0 && metas[0].content != "") { const gaaNum = metas[0].content; if (gaaNum.startsWith("UA-")) { (function (i, s, o, g, r, a, m) { i["GoogleAnalyticsObject"] = r; i[r] = i[r] || function () { (i[r].q = i[r].q || []).push(arguments) }, i[r].l = 1 * new Date; a = s.createElement(o), m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) })(window, document, "script", "//www.google-analytics.com/analytics.js", "ga"); ga("create", gaaNum, window.getCelDomain()); ga("set", "anonymizeIp", true); ga("send", "pageview"); console.log("finish initalizing google universal analytics.", gaaNum) } else { (function (d, o, g, s, m) { s = d.createElement(o); m = d.getElementsByTagName(o)[0]; s.async = 1; s.src = g; m.parentNode.insertBefore(s, m) })(document, "script", "https://www.googletagmanager.com/gtag/js?id=" + gaaNum); window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments) } gtag("js", new Date); gtag("config", gaaNum); console.log("finish initalizing google analytics v4.", gaaNum) } } }); document.addEventListener("DOMContentLoaded", function () { if (typeof $j("img[usemap]").rwdImageMaps !== "undefined") { $j("img[usemap]").rwdImageMaps() } }); document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.presentation && CELEMENTS.presentation.getOverlayObj && CELEMENTS.presentation.getOverlayObj()) { CELEMENTS.presentation.getOverlayObj({ overlayLayout: "SimpleLayout" }).registerOpenHandler() } }); let mobileDim = null; const cel_updateOrientationCSSclasses = function () { const innerWidth = mobileDim.getInnerWidth(); const innerHeight = mobileDim.getInnerHeight(); if (innerWidth > innerHeight) { $(document.body).removeClassName("cel_orientation_portrait"); $(document.body).addClassName("cel_orientation_landscape") } else { $(document.body).removeClassName("cel_orientation_landscape"); $(document.body).addClassName("cel_orientation_portrait") } }; document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.mobile && CELEMENTS.mobile.Dimensions) { mobileDim = new CELEMENTS.mobile.Dimensions; Event.stopObserving(window, "orientationchange", cel_updateOrientationCSSclasses); Event.observe(window, "orientationchange", cel_updateOrientationCSSclasses) } }); const cel_initAllMultiselect = function (event) { console.debug("initAllMultiselect"); if ($j().multiselect != undefined) { $j(".celBootstrap,.celMultiselect").filter(":visible,.celForceMultiselect").each(function (index, element) { if (!$(element).up(".cel_template")) { console.debug("initAllMultiselect: ", element); cel_initAllMultiselect_element(element) } }) } else { console.debug("initAllMultiselect: bootstrap multiselect undefined") } }; const cel_initAllMultiselect_element = function (element) { let params = { numberDisplayed: 3, onDropdownHidden: cel_initAllMultiselect_onDropdownHidden, onChange: cel_initAllMultiselect_onChange }; let bootstrapCfg = element.getAttribute("data-bootstrapConfig"); if (!bootstrapCfg && element.getAttribute("data-multiselectAttr")) { bootstrapCfg = element.getAttribute("data-multiselectAttr"); console.warn("initAllMultiselect: deprecated data-multiselectAttr in use", element) } if (bootstrapCfg) { params = $j.extend(params, JSON.parse(bootstrapCfg)) } const multiselect = $j(element).multiselect(params); $(document.body).fire("cel:multiselectInitialized", { multiselect: multiselect }) }; const cel_initAllMultiselect_onDropdownHidden = function (event) { $j(event.target).css("display", ""); event.target.fire("cel:multiselectOnDropdownHidden") }; const cel_initAllMultiselect_onChange = function (option, checked, select) { const multiselectElement = this; console.debug("fire cel:multiselectOnChange on: ", multiselectElement); $(option[0]).fire("cel:multiselectOnChange", { multiselect: multiselectElement, checked: checked, select: select }) }; const cel_initAllMultiselect_tabMenuPanel = function (event) { $("tabMenuPanel").select(".celBootstrap,.celMultiselect").each(function (element) { if (element.visible()) { element.addClassName("celForceMultiselect") } }); cel_initAllMultiselect(event) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initMultiselect", cel_initAllMultiselect); $(document.body).stopObserving("celements:contentChanged", cel_initAllMultiselect); $(document.body).observe("cel:initMultiselect", cel_initAllMultiselect); $(document.body).observe("celements:contentChanged", cel_initAllMultiselect); if ($("tabMenuPanel")) { $("tabMenuPanel").stopObserving("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel); $("tabMenuPanel").observe("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel) } $(document.body).fire("cel:initMultiselect") }); const cel_addMaxDimToFluidImg = function (event) { $$("img.cel_fluidresizeWidth").each(function (imgElem) { imgElem.setStyle({ maxWidth: imgElem.readAttribute("width") + "px" }) }); $$("img.cel_fluidresizeHeight").each(function (imgElem) { imgElem.setStyle({ maxHeight: imgElem.readAttribute("height") + "px" }) }) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).stopObserving("celements:contentChanged", cel_addMaxDimToFluidImg); $(document.body).observe("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).observe("celements:contentChanged", cel_addMaxDimToFluidImg) }); document.addEventListener("DOMContentLoaded", function () { $$(".generalOverlayWrapper .generalOverlay .exitOnClose").each(function (elem) { elem.stopObserving("click", cel_closeOverlayWindow); elem.observe("click", cel_closeOverlayWindow) }) }); const cel_closeOverlayWindow = function (event) { event.stop(); window.close() }; const updateCelMessages = function () { if (typeof $j.format !== "undefined") { $j.format.locale({ date: celMessages.jqueryFormater }) } }; document.addEventListener("DOMContentLoaded", function () { if (window.celMessages.isLoaded && typeof celMessages.jqueryFormater === "object") { updateCelMessages() } else { $(document.body).observe("cel:messagesLoaded", updateCelMessages) } }) })(window); +(function (window, undefined) { "use strict"; if (typeof window.console === "undefined") { window.console = {} } if (typeof window.console.error === "undefined") { window.console.error = Prototype.emptyFunction } if (typeof window.console.warn === "undefined") { window.console.warn = window.console.error } if (typeof window.console.info === "undefined") { window.console.info = window.console.warn } if (typeof window.console.log === "undefined") { window.console.log = window.console.info } if (typeof window.console.debug === "undefined") { window.console.debug = window.console.log } if (typeof window.CELEMENTS === "undefined") { window.CELEMENTS = {} } if (typeof window.CELEMENTS.mixins === "undefined") { window.CELEMENTS.mixins = {} } if (typeof window.CELEMENTS.mixins.Event === "undefined") { window.CELEMENTS.mixins.Event = Class.create({ memo: undefined, stopped: undefined, eventName: undefined, type: undefined, detail: undefined, cancelable: undefined, defaultPrevented: undefined, target: undefined, initialize: function (eventName, memo, target) { this.memo = memo; this.eventName = eventName; this.stopped = false; this.type = eventName; this.detail = memo; this.cancelable = true; this.defaultPrevented = false; this.target = target || (memo ? memo.target : null) }, stop: function () { if (this.cancelable) { this.stopped = true; this.defaultPrevented = true } }, preventDefault: function () { this.stop() }, findElement: function () { return this.target } }) } if (typeof window.CELEMENTS.mixins.Observable === "undefined") { window.CELEMENTS.mixins.Observable = { _celEventMap: null, _getCelEventMap: function (eventKey) { if (!this._celEventMap) { this._celEventMap = new Map } if (eventKey) { if (!this._celEventMap.has(eventKey)) { this._celEventMap.set(eventKey, []) } return this._celEventMap.get(eventKey) } return this._celEventMap }, celObserve: function (eventKey, callbackFN) { console.debug("cel celObserve:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celObserve call" } this._getCelEventMap(eventKey).push(callbackFN) }, celStopObserving: function (eventKey, callbackFN) { console.debug("cel celStopObserving:", eventKey, callbackFN); if (!eventKey) { throw "undefined eventKey in celStopObserving call" } this._getCelEventMap().set(eventKey, this._getCelEventMap(eventKey).filter(function (fn) { return fn !== callbackFN })) }, celFire: function (eventKey, memo) { if (!eventKey) { throw "undefined eventKey in celFire call" } const event = new CELEMENTS.mixins.Event(eventKey, memo, this); const listeners = this._getCelEventMap(eventKey); console.debug("cel celFire:", event, "on", listeners); listeners.forEach(function (callbackFN) { try { callbackFN(event) } catch (exp) { console.error("listener in celFire failed for event", eventKey, callbackFN, exp) } }); return event } } } let celOnBeforeLoadListenerArray = []; window.celAddOnBeforeLoadListener = function (listenerFunc) { console.warn("celAddOnBeforeLoad is deprecated since open-celements 5.4 / January 2022." + ' Instead register a listener on "DOMContentLoaded"', listenerFunc); celOnBeforeLoadListenerArray.push(listenerFunc) }; document.addEventListener("DOMContentLoaded", function () { celOnBeforeLoadListenerArray.forEach(function (listener) { try { listener() } catch (e) { console.error("Listener for celOnBeforeLoad failed: ", e) } }); $(document.body).fire("celements:beforeOnLoad") }); let celOnFinishHeaderListenerArray = []; window.celAddOnFinishHeaderListener = function (listenerFunc) { celOnFinishHeaderListenerArray.push(listenerFunc) }; window.celFinishHeaderHandler = function () { celOnFinishHeaderListenerArray.forEach(function (listener) { try { listener() } catch (exp) { console.error("Failed to execute celOnFinishHeader listener. ", exp) } }) }; if (typeof window.getCelDomain === "undefined") { window.getCelDomain = function () { const hostName = window.location.host; return hostName.replace(/^www\./, "") } } if (typeof window.CELEMENTS.LoadingIndicator === "undefined") { window.CELEMENTS.LoadingIndicator = Class.create({ _loadingImg: undefined, initialize: function () { const _me = this; _me._loadingImg = new Hash }, getLoadingIndicator: function (isSmallOrPxSize) { const _me = this; let loaderType = "ajax-loader-32px"; if (typeof isSmallOrPxSize === "boolean") { if (isSmallOrPxSize) { loaderType = "ajax-loader-16px" } } else if (typeof isSmallOrPxSize === "number") { loaderType = "ajax-loader-" + isSmallOrPxSize + "px" } if (!_me._loadingImg.get(loaderType)) { _me._loadingImg.set(loaderType, new Element("img", { src: CELEMENTS.getUtils().getPathPrefix() + "/file/resources/celRes/spinner/" + loaderType + ".png", class: "editorLoading", alt: "loading..." })) } return _me._loadingImg.get(loaderType).clone() } }) } if (typeof window.CELEMENTS.Utils === "undefined") { window.CELEMENTS.Utils = Class.create({ _srcOriginHost: undefined, getPathPrefix: function () { const _me = this; if (!_me._srcOriginHost) { let srcOriginHost = null; const scripts = document.getElementsByTagName("script"); let len = scripts.length; const re = new RegExp("(https?://[^/]*)/(([^/]*/)*)resources/celJS/initCelements(.min)?\\.js(\\?.*)?$"); let src; while (len--) { src = scripts[len].src; const srcMatches = src.match(re); if (src && srcMatches) { srcOriginHost = srcMatches[1]; const prefixPath = srcMatches[2]; const prefixPathSplit = prefixPath.split("/"); const prefixStr = prefixPathSplit.splice(0, prefixPathSplit.length - 2).join("/"); if (prefixStr != "") { srcOriginHost += "/" + prefixStr } break } } console.log("getPathPrefix computed prefixPath: ", srcOriginHost); _me._srcOriginHost = srcOriginHost } return _me._srcOriginHost }, convertFullNameToViewURL: function (fullName) { const _me = this; return _me.getPathPrefix() + ("/" + fullName.replace(/\./, "/")).replace(/\/Content\//, "/") } }); const globalUtilsInstance = new window.CELEMENTS.Utils; window.CELEMENTS.getUtils = function () { return globalUtilsInstance } } if (typeof window.CELEMENTS.getPathPrefix === "undefined") { window.CELEMENTS.getPathPrefix = function () { console.warn("deprecated call of window.CELEMENTS.getPathPrefix." + " Instead use window.CELEMENTS.getUtils().getPathPrefix()"); return window.CELEMENTS.getUtils().getPathPrefix() } } if (typeof window.getCelHost === "undefined") { window.getCelHost = function () { let celHost = document.location + "?"; if (document.location.pathname.indexOf("/skin/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/skin/resources/")) } else if (document.location.pathname.indexOf("/file/resources/") > -1) { celHost = celHost.substring(0, celHost.indexOf("/file/resources/")) } else { celHost = celHost.substring(0, celHost.indexOf("?")) } return celHost } } if (typeof window.CELEMENTS.Ajax === "undefined") { window.CELEMENTS.Ajax = {} } if (typeof window.CELEMENTS.Ajax.Reconnector === "undefined") { window.CELEMENTS.Ajax.Reconnector = Class.create({ _htmlElem: undefined, _callbackOnSuccess: undefined, _reconnectWait: undefined, _reconnectorHandlerBind: undefined, _cancelAjaxOnTimeoutBind: undefined, _reconnectorExecuter: undefined, _reconnectWaitStart: undefined, _minReconnectWait: undefined, _maxReconnectWait: undefined, _url: undefined, _configObj: undefined, initialize: function (htmlElemId, callbackOnSuccess, configObj) { const _me = this; _me._htmlElem = $(htmlElemId); _me._configObj = configObj || {}; _me._url = _me._configObj.url || window.getCelHost(); _me._callbackOnSuccess = callbackOnSuccess; _me._reconnectorHandlerBind = _me._reconnectorHandler.bind(_me); _me._cancelAjaxOnTimeoutBind = _me._cancelAjaxOnTimeout.bind(_me); _me._minReconnectWait = _me._configObj.minReconnectWait || 10; _me._maxReconnectWait = _me._configObj.maxReconnectWait || 30; _me._reset() }, _reset: function () { const _me = this; _me._reconnectWaitStart = _me._minReconnectWait }, setMinRecconectWait: function (minReconnectWait) { const _me = this; _me._minReconnectWait = minReconnectWait }, setMaxRecconectWait: function (maxReconnectWait) { const _me = this; _me._maxReconnectWait = maxReconnectWait }, _fireAjaxRecconectTrying: function () { const _me = this; return _me._htmlElem.fire("celements:AjaxReconnectTrying", _me._reconnectWait) }, _reconnectorHandler: function () { const _me = this; _me._reconnectWait--; if (_me._reconnectWait == 0) { _me._reconnectorExecuter.stop(); if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Trying..."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryNotice } _me._htmlElem.update(mesg) } _me._connectionTester() } else { if (!_me._fireAjaxRecconectTrying().stopped && !_me._configObj.skipRetryMsg) { let mesg = "Retrying in {} seconds."; if (window.celMessages && window.celMessages.Reconnector) { mesg = window.celMessages.Reconnector.retryDelayNotice } mesg = mesg.replace("{}", _me._reconnectWait); _me._htmlElem.update(mesg); _me._htmlElem.fire("celements:AjaxReconnectFailed") } } }, start: function () { const _me = this; _me._reconnectWait = _me._reconnectWaitStart; _me._reconnectorExecuter = new PeriodicalExecuter(_me._reconnectorHandlerBind, 1) }, _cancelAjaxOnTimeout: function (ajaxCall) { if (!ajaxCall._complete) { ajaxCall.transport.abort() } }, _connectionTester: function () { const _me = this; const connectionTestAjax = new Ajax.Request(_me._url, { parameters: { ajax: 1, xpage: "celements_ajax", ajax_mode: "pageTypeWithLayout", overwriteLayout: "SimpleLayout" }, onSuccess: function () { _me._reset(); _me._reconnectorExecuter = null; _me._callbackOnSuccess(); _me._htmlElem.fire("celements:AjaxReconnectSuccess") }, onFailure: function () { _me._reconnectWaitStart = Math.min(_me._reconnectWaitStart * 2, _me._maxReconnectWait); _me.start() } }); _me._cancelAjaxOnTimeoutBind.delay(10, connectionTestAjax) } }) } window.CELEMENTS.UrlUtils = Class.create({ getParams: function (search) { const _me = this; search = search || window.location.search; const paramSplit = search.split(new RegExp("[?&]")); paramSplit.unshift(new Hash); return paramSplit.reduce(_me._splitUriSearch.bind(_me)) || new Hash }, joinParams: function (hash) { let paramsArray = []; $H(hash).each(function (pair) { const pairMapped = pair.value.map(function (elem) { return pair.key + "=" + encodeURI(elem) }); paramsArray = paramsArray.concat(pairMapped) }); return paramsArray.join("&") }, _splitUriSearch: function (paramHash, elem) { let key = elem.split("=", 1); if (key.length > 0 && key[0].length > 0) { key = key[0]; const val = decodeURI(elem.substring(key.length + 1)); if (!paramHash.get(key)) { paramHash.set(key, [val]) } else { paramHash.get(key).push(val) } } return paramHash } }); window.celMessages = {}; window.celMessages.isLoaded = false; try { new Ajax.Request("/api/v1/messages", { method: "get", onSuccess: function (transport) { if (transport.responseText.isJSON()) { const newMessages = transport.responseText.evalJSON(); console.log("initCelements.js: finished getting dictionary messages."); newMessages.isLoaded = true; window.celMessages = newMessages; celMessagesCbFnArray.each(function (callbackFn) { try { callbackFn(newMessages) } catch (exp) { console.error("Failed to execute callbackFn!", exp) } }); $(document.body).fire("cel:messagesLoaded", newMessages) } else { console.error("noJSON!!! ", transport.responseText) } } }) } catch (exp) { console.error("Failed to get Cel-Messages async!", exp) } const celMessagesCbFnArray = []; window.celExecOnceAfterMessagesLoaded = function (callbackFn) { if (!celMessagesCbFnArray.includes(callbackFn)) { celMessagesCbFnArray.push(callbackFn); if (window.celMessages.isLoaded) { callbackFn(window.celMessages) } } }; if (typeof window.CELEMENTS.CssClassEventHandler === "undefined") { window.CELEMENTS.CssClassEventHandler = Class.create({ _htmlElement: undefined, _eventName: undefined, _cssSelector: undefined, _className: undefined, _actionFunction: undefined, _conditionFunction: undefined, _actionHandlerBind: undefined, initialize: function (htmlElement, eventName, cssSelector, className, actionFunction, condition) { const _me = this; _me._htmlElement = $(htmlElement); _me._eventName = eventName; _me._cssSelector = cssSelector; _me._className = className; _me._actionFunction = actionFunction; if (condition && !/\s|;/.test(condition)) { _me._conditionFunction = new Function("me", "origin", "return " + condition + ";") } _me._actionHandlerBind = _me._actionHandler.bind(_me); _me._registerActionHandler() }, _registerActionHandler: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); Event.observe(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - register: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) }, _actionHandler: function (event) { const _me = this; _me._getTargetElements().each(function (targetElement) { if (!_me._conditionFunction || _me._conditionFunction(targetElement, _me._htmlElement)) { _me._actionFunction(targetElement, _me._className); console.debug("EventHandler - upon", _me._eventName, "action [", _me._actionFunction.name, _me._className, "] executed on", targetElement) } else { console.debug("EventHandler - action skipped for failed condition [", _me._conditionFunction, "] on ", targetElement) } }) }, _getTargetElements: function () { const _me = this; if (_me._cssSelector.startsWith("^")) { parent = _me._htmlElement.up(_me._cssSelector.substring(1)); return parent ? [parent] : [] } else { return $$(_me._cssSelector) } }, unregister: function () { const _me = this; Event.stopObserving(_me._htmlElement, _me._eventName, _me._actionHandlerBind); console.debug("EventHandler - unregister: ", _me._eventName, _me._cssSelector, _me._className, _me._actionFunction.name, _me._htmlElement) } }) } if (typeof window.CELEMENTS.EventManager === "undefined") { window.CELEMENTS.EventManager = Class.create({ _instructionRegex: new RegExp(/([\w:]+)([%+-])([\w-]+):([^?]+)\??(.+)?/), _actionFunctionMap: { "+": Element.addClassName, "-": Element.removeClassName, "%": Element.toggleClassName }, _eventElements: undefined, _eventElemCounter: undefined, _interpretDataCelEventBind: undefined, _contentChangedHandlerBind: undefined, _intersectionObserver: undefined, _intersectionValues: [], initialize: function () { const _me = this; _me._eventElements = new Array; _me._eventElemCounter = 0; _me._interpretDataCelEventBind = _me._interpretDataCelEvent.bind(_me); _me._contentChangedHandlerBind = _me._contentChangedHandler.bind(_me); try { _me._intersectionObserver = new IntersectionObserver(function (entries) { entries.forEach(_me._handleIntersection.bind(_me)) }, { threshold: [0, .5, 1] }) } catch (exp) { console.warn("EventManager - initialize: IntersectionObserver not available", exp) } }, _splitDataCelEventList: function (dataValue) { let ret = new Array; if (dataValue) { ret = dataValue.replace(/([^&])&([^&])/g, "$1#SPLIT#$2").split("#SPLIT#") } return ret }, _parseEventInstruction: function (instruction) { const _me = this; const parts = instruction.match(_me._instructionRegex) || []; const data = { eventName: parts[1], action: parts[2], className: parts[3], cssSelector: parts[4], condition: parts[5] }; if (data.eventName && data.action && data.className && data.cssSelector) { return data } else { throw "parseEventInstruction: unable to parse event instruction '" + instruction + "'" } }, _createEventHandler: function (htmlElem, instruction) { const _me = this; const data = _me._parseEventInstruction(instruction); const actionFunction = _me._actionFunctionMap[data.action]; if (actionFunction) { if (_me._intersectionObserver && (data.eventName.startsWith("cel:enter") || data.eventName.startsWith("cel:leave"))) { _me._intersectionObserver.observe(htmlElem); console.debug("EventManager - observing intersection", htmlElem.dataset.celEventNb, data) } return new window.CELEMENTS.CssClassEventHandler(htmlElem, data.eventName, data.cssSelector, data.className, actionFunction, data.condition) } else { throw "createEventHandler: unknown action '" + data.action + '"' } }, _createEventElement: function (htmlElem) { const _me = this; const dataValue = htmlElem.dataset.celEvent; return { htmlElem: htmlElem, dataValue: dataValue, eventHandlers: _me._splitDataCelEventList(dataValue).map(function (instruction) { try { return _me._createEventHandler(htmlElem, instruction) } catch (exp) { console.error("EventManager - interpretData: invalid instruction ", exp, htmlElem) } }).filter(Boolean) } }, _interpretDataCelEvent: function (htmlElem) { const _me = this; const logPref = "EventManager - interpretData: "; if (htmlElem.classList.contains("celOnEventInit")) { console.debug(logPref, "skip already initialized: ", htmlElem) } else if (htmlElem.up(".cel_template")) { console.debug(logPref, "skip template element: ", htmlElem) } else { htmlElem.dataset.celEventNb = ++_me._eventElemCounter; const newElem = _me._createEventElement(htmlElem); if (newElem.eventHandlers.length > 0) { _me._eventElements.push(newElem) } else { console.warn(logPref, "no valid instructions found on ", htmlElem) } htmlElem.classList.add("celOnEventInit"); $(htmlElem).fire("celEM:init") } }, _handleIntersection: function (entry) { const _me = this; const htmlElem = entry.target; const eventNb = htmlElem.dataset.celEventNb; const previous = _me._intersectionValues[eventNb] || Object.freeze({ y: Number.MAX_SAFE_INTEGER, ratio: 0 }); const current = Object.freeze({ y: entry.boundingClientRect.y, ratio: entry.intersectionRatio }); const direction = current.y > previous.y ? "up" : "down"; const type = entry.isIntersecting && current.ratio >= previous.ratio ? "enter" : "leave"; const ratioA = type === "enter" ? current.ratio : previous.ratio; const ratioB = type === "leave" ? current.ratio : previous.ratio; const steps = []; if (ratioA >= 1 && ratioB < 1) steps.push(":full"); if (ratioA >= .5 && ratioB < .5) steps.push(":half"); if (ratioA > 0 && ratioB <= 0) steps.push(""); steps.forEach(function (step) { ["cel:" + type + step, "cel:" + type + step + ":" + direction].forEach(function (eventName) { console.debug("EventManager - intersect", eventName, "on", eventNb, previous, "->", current); htmlElem.fire(eventName) }) }); _me._intersectionValues[eventNb] = current }, _contentChangedHandler: function (event) { const _me = this; console.debug("EventManager - contentChanged ", event); if (event.memo && event.memo.htmlElem) { _me.updateCelEventHandlers(event.memo.htmlElem) } else { _me.updateCelEventHandlers() } }, updateCelEventHandlers: function (htmlContainer) { const _me = this; const rootElem = htmlContainer || document.body; Event.stopObserving($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); Event.observe($(document.body), "celements:contentChanged", _me._contentChangedHandlerBind); _me._removeDisappearedElems(); rootElem.querySelectorAll(".celOnEvent").forEach(_me._interpretDataCelEventBind) }, _removeDisappearedElems: function () { const _me = this; for (let i = _me._eventElements.length - 1; i >= 0; i--) { const elem = _me._eventElements[i]; const isInBody = $(document.body).contains(elem.htmlElem); const changedDataValue = elem.htmlElem.dataset.celEvent !== elem.dataValue; if (!isInBody || changedDataValue || !elem.htmlElem.classList.contains("celOnEventInit")) { elem.eventHandlers.forEach(function (handler) { handler.unregister() }); _me._eventElements.splice(i, 1); elem.htmlElem.classList.remove("celOnEventInit"); console.debug("EventManager - removeDisappearedElem: ", elem) } } } }); window.CELEMENTS.globalEventManager = new window.CELEMENTS.EventManager; document.addEventListener("DOMContentLoaded", window.CELEMENTS.globalEventManager._contentChangedHandlerBind) } const formValidations = new Hash; const registerValidation = function (formElem) { if (formElem && formElem.id) { const valid = new Validation(formElem, { immediate: true, useTitles: true, stopOnFirst: false }); formValidations.set(formElem.id, valid) } else { console.error("failed to register validation on form with no id. ", formElem) } }; document.addEventListener("DOMContentLoaded", function () { $$("form.cel_form_validation").each(registerValidation); $(document.body).observe("cel_yuiOverlay:contentChanged", function (event) { const containerElem = event.findElement(); if (containerElem) { containerElem.select("form.cel_form_validation").each(registerValidation) } }) }); window.celAddOnFinishHeaderListener(function () { const metas = $$('meta[name="cel-GAA-Num"]'); if (metas.size() > 0 && metas[0].content != "") { const gaaNum = metas[0].content; if (gaaNum.startsWith("UA-")) { (function (i, s, o, g, r, a, m) { i["GoogleAnalyticsObject"] = r; i[r] = i[r] || function () { (i[r].q = i[r].q || []).push(arguments) }, i[r].l = 1 * new Date; a = s.createElement(o), m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) })(window, document, "script", "//www.google-analytics.com/analytics.js", "ga"); ga("create", gaaNum, window.getCelDomain()); ga("set", "anonymizeIp", true); ga("send", "pageview"); console.log("finish initalizing google universal analytics.", gaaNum) } else { (function (d, o, g, s, m) { s = d.createElement(o); m = d.getElementsByTagName(o)[0]; s.async = 1; s.src = g; m.parentNode.insertBefore(s, m) })(document, "script", "https://www.googletagmanager.com/gtag/js?id=" + gaaNum); window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments) } gtag("js", new Date); gtag("config", gaaNum); console.log("finish initalizing google analytics v4.", gaaNum) } } }); document.addEventListener("DOMContentLoaded", function () { if (typeof $j("img[usemap]").rwdImageMaps !== "undefined") { $j("img[usemap]").rwdImageMaps() } }); document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.presentation && CELEMENTS.presentation.getOverlayObj && CELEMENTS.presentation.getOverlayObj()) { CELEMENTS.presentation.getOverlayObj({ overlayLayout: "SimpleLayout" }).registerOpenHandler() } }); let mobileDim = null; const cel_updateOrientationCSSclasses = function () { const innerWidth = mobileDim.getInnerWidth(); const innerHeight = mobileDim.getInnerHeight(); if (innerWidth > innerHeight) { $(document.body).removeClassName("cel_orientation_portrait"); $(document.body).addClassName("cel_orientation_landscape") } else { $(document.body).removeClassName("cel_orientation_landscape"); $(document.body).addClassName("cel_orientation_portrait") } }; document.addEventListener("DOMContentLoaded", function () { if (CELEMENTS && CELEMENTS.mobile && CELEMENTS.mobile.Dimensions) { mobileDim = new CELEMENTS.mobile.Dimensions; Event.stopObserving(window, "orientationchange", cel_updateOrientationCSSclasses); Event.observe(window, "orientationchange", cel_updateOrientationCSSclasses) } }); const cel_initAllMultiselect = function (event) { console.debug("initAllMultiselect"); if ($j().multiselect != undefined) { $j(".celBootstrap,.celMultiselect").filter(":visible,.celForceMultiselect").each(function (index, element) { if (!$(element).up(".cel_template")) { console.debug("initAllMultiselect: ", element); cel_initAllMultiselect_element(element) } }) } else { console.debug("initAllMultiselect: bootstrap multiselect undefined") } }; const cel_initAllMultiselect_element = function (element) { let params = { numberDisplayed: 3, onDropdownHidden: cel_initAllMultiselect_onDropdownHidden, onChange: cel_initAllMultiselect_onChange }; let bootstrapCfg = element.getAttribute("data-bootstrapConfig"); if (!bootstrapCfg && element.getAttribute("data-multiselectAttr")) { bootstrapCfg = element.getAttribute("data-multiselectAttr"); console.warn("initAllMultiselect: deprecated data-multiselectAttr in use", element) } if (bootstrapCfg) { params = $j.extend(params, JSON.parse(bootstrapCfg)) } const multiselect = $j(element).multiselect(params); $(document.body).fire("cel:multiselectInitialized", { multiselect: multiselect }) }; const cel_initAllMultiselect_onDropdownHidden = function (event) { $j(event.target).css("display", ""); event.target.fire("cel:multiselectOnDropdownHidden") }; const cel_initAllMultiselect_onChange = function (option, checked, select) { const multiselectElement = this; console.debug("fire cel:multiselectOnChange on: ", multiselectElement); $(option[0]).fire("cel:multiselectOnChange", { multiselect: multiselectElement, checked: checked, select: select }) }; const cel_initAllMultiselect_tabMenuPanel = function (event) { $("tabMenuPanel").select(".celBootstrap,.celMultiselect").each(function (element) { if (element.visible()) { element.addClassName("celForceMultiselect") } }); cel_initAllMultiselect(event) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initMultiselect", cel_initAllMultiselect); $(document.body).stopObserving("celements:contentChanged", cel_initAllMultiselect); $(document.body).observe("cel:initMultiselect", cel_initAllMultiselect); $(document.body).observe("celements:contentChanged", cel_initAllMultiselect); if ($("tabMenuPanel")) { $("tabMenuPanel").stopObserving("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel); $("tabMenuPanel").observe("tabedit:tabLoadingFinished", cel_initAllMultiselect_tabMenuPanel) } $(document.body).fire("cel:initMultiselect") }); const cel_addMaxDimToFluidImg = function (event) { $$("img.cel_fluidresizeWidth").each(function (imgElem) { imgElem.setStyle({ maxWidth: imgElem.readAttribute("width") + "px" }) }); $$("img.cel_fluidresizeHeight").each(function (imgElem) { imgElem.setStyle({ maxHeight: imgElem.readAttribute("height") + "px" }) }) }; document.addEventListener("DOMContentLoaded", function () { $(document.body).stopObserving("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).stopObserving("celements:contentChanged", cel_addMaxDimToFluidImg); $(document.body).observe("cel:initFluidImage", cel_addMaxDimToFluidImg); $(document.body).observe("celements:contentChanged", cel_addMaxDimToFluidImg) }); document.addEventListener("DOMContentLoaded", function () { $$(".generalOverlayWrapper .generalOverlay .exitOnClose").each(function (elem) { elem.stopObserving("click", cel_closeOverlayWindow); elem.observe("click", cel_closeOverlayWindow) }) }); const cel_closeOverlayWindow = function (event) { event.stop(); window.close() }; const updateCelMessages = function () { if (typeof $j.format !== "undefined") { $j.format.locale({ date: celMessages.jqueryFormater }) } }; document.addEventListener("DOMContentLoaded", function () { if (window.celMessages.isLoaded && typeof celMessages.jqueryFormater === "object") { updateCelMessages() } else { $(document.body).observe("cel:messagesLoaded", updateCelMessages) } }) })(window); diff --git a/celements-webapp/src/main/webapp/resources/celJS/validation.js b/celements-webapp/src/main/webapp/resources/celJS/validation.js index 7fa587cee..1e5e83f66 100644 --- a/celements-webapp/src/main/webapp/resources/celJS/validation.js +++ b/celements-webapp/src/main/webapp/resources/celJS/validation.js @@ -539,7 +539,7 @@ ['validate-docname', null, Validator.methods.validDocName], ]; - new Ajax.Request(document.querySelector('meta[name="celements-validation-messages-url"]').content, { + new Ajax.Request('/api/v1/messages/validation', { method: 'get', onSuccess: function (transport) { if (transport.responseText.isJSON()) { diff --git a/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm b/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm index b8b2b92fa..c0c385bc4 100644 --- a/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm +++ b/celements-webapp/src/main/webapp/templates/celAjax/FlowplayerInOverlay.vm @@ -2,7 +2,6 @@ - #set($jsService = $services.javascript) #set($extJsParamSync = $!jsService.createExtJSParam().setAction('file')) diff --git a/celements-webapp/src/main/webapp/templates/celAjax/Messages.vm b/celements-webapp/src/main/webapp/templates/celAjax/Messages.vm deleted file mode 100644 index 778009a52..000000000 --- a/celements-webapp/src/main/webapp/templates/celAjax/Messages.vm +++ /dev/null @@ -1,5 +0,0 @@ -#set($jsonBuilder = $services.celementsweb.getNewJSONBuilder()) -$jsonBuilder.openDictionary() -#parse('celMacros/CelMessages.vm') -$jsonBuilder.closeDictionary() -$jsonBuilder.getJSON() \ No newline at end of file diff --git a/celements-webapp/src/main/webapp/templates/celAjax/ValidationMessages.vm b/celements-webapp/src/main/webapp/templates/celAjax/ValidationMessages.vm deleted file mode 100644 index 147d9e50b..000000000 --- a/celements-webapp/src/main/webapp/templates/celAjax/ValidationMessages.vm +++ /dev/null @@ -1,5 +0,0 @@ -#set($jsonBuilder = $services.celementsweb.getNewJSONBuilder()) -$jsonBuilder.openDictionary() -#parse('celMacros/CelValidationMessages.vm') -$jsonBuilder.closeDictionary() -$jsonBuilder.getJSON() \ No newline at end of file diff --git a/celements-webapp/src/main/webapp/templates/celMacros/CelMessages.vm b/celements-webapp/src/main/webapp/templates/celMacros/CelMessages.vm deleted file mode 100644 index fc2460384..000000000 --- a/celements-webapp/src/main/webapp/templates/celMacros/CelMessages.vm +++ /dev/null @@ -1,215 +0,0 @@ -$jsonBuilder.openProperty('celmeta') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('language', "$language") -$jsonBuilder.addStringProperty('admin-language', "$admin_language") -$jsonBuilder.addStringProperty('contextPath', "${request.contextPath}") -$jsonBuilder.addStringProperty('database', "${context.database}") -$jsonBuilder.openProperty('isAdmin') -$jsonBuilder.addBoolean($isAdmin) -$jsonBuilder.openProperty('isSuperAdmin') -$jsonBuilder.addBoolean($isSuperAdmin) -$jsonBuilder.addStringProperty('startupTimeStamp', "${services.celementsweb.getLastStartupTimeStamp()}") -$jsonBuilder.closeDictionary() -## Reconnector -$jsonBuilder.openProperty('Reconnector') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('retryNotice', "$!adminMsg.get('cel_reconnector_retryNotice')") -$jsonBuilder.addStringProperty('retryDelayNotice', "$!adminMsg.get('cel_reconnector_retryDelayNotice')") -$jsonBuilder.closeDictionary() -## jquery.formater -$jsonBuilder.openProperty('jqueryFormater') -$jsonBuilder.openDictionary() -$jsonBuilder.openProperty('monthsFull') -$jsonBuilder.openArray() -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_january')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_february')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_march')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_april')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_may')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_june')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_july')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_august')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_september')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_october')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_november')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsFull_december')") -$jsonBuilder.closeArray() -$jsonBuilder.openProperty('monthsShort') -$jsonBuilder.openArray() -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_january')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_february')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_march')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_april')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_may')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_june')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_july')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_august')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_september')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_october')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_november')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_monthsShort_december')") -$jsonBuilder.closeArray() -$jsonBuilder.openProperty('daysFull') -$jsonBuilder.openArray() -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysFull_sunday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysFull_monday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysFull_tuesday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysFull_wednesday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysFull_thursday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysFull_friday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysFull_saturday')") -$jsonBuilder.closeArray() -$jsonBuilder.openProperty('daysShort') -$jsonBuilder.openArray() -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysShort_sunday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysShort_monday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysShort_tuesday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysShort_wednesday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysShort_thursday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysShort_friday')") -$jsonBuilder.addString("$!adminMsg.get('cel_date_formater_daysShort_saturday')") -$jsonBuilder.closeArray() -$jsonBuilder.closeDictionary() -## celements photo slideShow -$jsonBuilder.openProperty('celslideshow') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('cmPause', "$!adminMsg.get('cel_slideshow_cm_pause')") -$jsonBuilder.addStringProperty('cmContinue', "$!adminMsg.get('cel_slideshow_cm_continue')") -$jsonBuilder.addStringProperty('cmOpenLink', "$!adminMsg.get('cel_slideshow_cm_openlink')") -$jsonBuilder.closeDictionary() -## celements admin importer (import.js) -$jsonBuilder.openProperty('celAdminImport') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('availableDocuments', "$!adminMsg.get('core.importer.availableDocuments')") -$jsonBuilder.addStringProperty('importHistoryLabel', "$!adminMsg.get('core.importer.importHistory')") -$jsonBuilder.addStringProperty('selectionEmpty', "$!adminMsg.get('core.importer.selectionEmptyWarning')") -$jsonBuilder.addStringProperty('import', "$!adminMsg.get('core.importer.import')") -$jsonBuilder.addStringProperty('package', "$!adminMsg.get('core.importer.package')") -$jsonBuilder.addStringProperty('description', "$!adminMsg.get('core.importer.package.description')") -$jsonBuilder.addStringProperty('version', "$!adminMsg.get('core.importer.package.version')") -$jsonBuilder.addStringProperty('licence', "$!adminMsg.get('core.importer.package.licence')") -$jsonBuilder.addStringProperty('author', "$!adminMsg.get('core.importer.package.author')") -$jsonBuilder.addStringProperty('documentSelected', "$!adminMsg.get('core.importer.documentSelected')") -$jsonBuilder.addStringProperty('whenDocumentAlreadyExists', "$!adminMsg.get('core.importer.whenDocumentAlreadyExists')") -$jsonBuilder.addStringProperty('addNewVersion', "$!adminMsg.get('core.importer.addNewVersion')") -$jsonBuilder.addStringProperty('replaceDocumentHistory', "$!adminMsg.get('core.importer.replaceDocumentHistory')") -$jsonBuilder.addStringProperty('resetHistory', "$!adminMsg.get('core.importer.resetHistory')") -$jsonBuilder.addStringProperty('importAsBackup', "$!adminMsg.get('core.importer.importAsBackup')") -$jsonBuilder.addStringProperty('select', "$!adminMsg.get('core.importer.select')") -$jsonBuilder.addStringProperty('all', "$!adminMsg.get('core.importer.selectAll')") -$jsonBuilder.addStringProperty('none', "$!adminMsg.get('core.importer.selectNone')") -$jsonBuilder.closeDictionary() -## celements menu -$jsonBuilder.openProperty('celmenu') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('supportLinkURL', "$!services.celementsweb.getSupportLinkURL()") -$jsonBuilder.closeDictionary() -## xwiki/actionButtons.js -$jsonBuilder.openProperty('actionButtons') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('cancel', "$!adminMsg.get('core.shortcuts.edit.cancel')") -$jsonBuilder.addStringProperty('preview', "$!adminMsg.get('core.shortcuts.edit.preview')") -$jsonBuilder.addStringProperty('backtoedit', "$!adminMsg.get('core.shortcuts.edit.backtoedit')") -$jsonBuilder.addStringProperty('saveandview', "$!adminMsg.get('core.shortcuts.edit.saveandview')") -$jsonBuilder.addStringProperty('saveandcontinue', "$!adminMsg.get('core.shortcuts.edit.saveandcontinue')") -$jsonBuilder.addStringProperty('mandatoryField', "$!adminMsg.get('core.editors.validation.mandatoryField')") -$jsonBuilder.addStringProperty('commentPrompt', "$!adminMsg.get('core.comment.prompt')") -$jsonBuilder.closeDictionary() -## xwiki/attachments.js -$jsonBuilder.openProperty('attachments') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('deleteConfirm', "$!adminMsg.get('core.viewers.attachments.delete.confirm')") -$jsonBuilder.addStringProperty('deleteInProgress', "$!adminMsg.get('core.viewers.attachments.delete.inProgress')") -$jsonBuilder.addStringProperty('deleteDone', "$!adminMsg.get('core.viewers.attachments.delete.done')") -$jsonBuilder.addStringProperty('deleteFailed', "$!adminMsg.get('core.viewers.attachments.delete.failed')") -$jsonBuilder.addStringProperty('addFileInput', "$!adminMsg.get('core.viewers.attachments.upload.addFileInput')") -$jsonBuilder.addStringProperty('removeFileInput', "$!adminMsg.get('core.viewers.attachments.upload.removeFileInput')") -$jsonBuilder.addStringProperty('removeFileInputTitle', "$!adminMsg.get('core.viewers.attachments.upload.removeFileInput.title')") -$jsonBuilder.addStringProperty('extranb', "$!adminMsg.get('docextra.extranb', ['__number__'])") -$jsonBuilder.closeDictionary() -## xwiki/code.js -$jsonBuilder.openProperty('code') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('showLineNumbers', "$!adminMsg.get('core.viewers.code.showLineNumbers')") -$jsonBuilder.addStringProperty('hideLineNumbers', "$!adminMsg.get('core.viewers.code.hideLineNumbers')") -$jsonBuilder.closeDictionary() -## xwiki/comments.js -$jsonBuilder.openProperty('comments') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('commentDeleted', "$!adminMsg.get('core.viewers.comments.commentDeleted')") -$jsonBuilder.addStringProperty('deleteConfirm', "$!adminMsg.get('core.viewers.comments.delete.confirm')") -$jsonBuilder.addStringProperty('deleteInProgress', "$!adminMsg.get('core.viewers.comments.delete.inProgress')") -$jsonBuilder.addStringProperty('deleteDone', "$!adminMsg.get('core.viewers.comments.delete.done')") -$jsonBuilder.addStringProperty('deleteFailed', "$!adminMsg.get('core.viewers.comments.delete.failed')") -$jsonBuilder.addStringProperty('editFormFetchInProgress', "$!adminMsg.get('core.viewers.comments.editForm.fetch.inProgress')") -$jsonBuilder.addStringProperty('editFormFetchFailed', "$!adminMsg.get('core.viewers.comments.editForm.fetch.failed')") -$jsonBuilder.addStringProperty('addInProgress', "$!adminMsg.get('core.viewers.comments.add.inProgress')") -$jsonBuilder.addStringProperty('addDone', "$!adminMsg.get('core.viewers.comments.add.done')") -$jsonBuilder.addStringProperty('addFailed', "$!adminMsg.get('core.viewers.comments.add.failed')") -$jsonBuilder.addStringProperty('previewButtonPreview', "$!adminMsg.get('core.viewers.comments.preview.button.preview')") -$jsonBuilder.addStringProperty('previewInProgress', "$!adminMsg.get('core.viewers.comments.preview.inProgress')") -$jsonBuilder.addStringProperty('previewFailed', "$!adminMsg.get('core.viewers.comments.preview.failed')") -$jsonBuilder.addStringProperty('previewButtonBack', "$!adminMsg.get('core.viewers.comments.preview.button.back')") -$jsonBuilder.addStringProperty('extranb', "$!adminMsg.get('docextra.extranb', ['__number__'])") -$jsonBuilder.closeDictionary() -## xwiki/confirmationBox.js -$jsonBuilder.openProperty('confirmationBox') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('defaultQuestion', "$!adminMsg.get('core.widgets.confirmationBox.defaultQuestion')") -$jsonBuilder.addStringProperty('yes', "$!adminMsg.get('core.widgets.confirmationBox.button.yes')") -$jsonBuilder.addStringProperty('no', "$!adminMsg.get('core.widgets.confirmationBox.button.no')") -$jsonBuilder.closeDictionary() -## xwiki/confirmedAjaxRequest.js -$jsonBuilder.openProperty('confirmedAjaxRequest') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('notificationInProgress', "$!adminMsg.get('core.widgets.confirmationBox.notification.inProgress')") -$jsonBuilder.addStringProperty('notificationDone', "$!adminMsg.get('core.widgets.confirmationBox.notification.done')") -$jsonBuilder.addStringProperty('notificationFailed', "$!adminMsg.get('core.widgets.confirmationBox.notification.failed')") -$jsonBuilder.closeDictionary() -## xwiki/dataeditors.js -$jsonBuilder.openProperty('dataeditors') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('confirmationText', "$!adminMsg.get('core.editors.object.delete.confirm')") -$jsonBuilder.addStringProperty('progressMessageText', "$!adminMsg.get('core.editors.object.delete.inProgress')") -$jsonBuilder.addStringProperty('successMessageText', "$!adminMsg.get('core.editors.object.delete.done')") -$jsonBuilder.addStringProperty('failureMessageText', "$!adminMsg.get('core.editors.object.delete.failed')") -$jsonBuilder.closeDictionary() -## xwiki/livetable.js -$jsonBuilder.openProperty('livetable') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('resultsOf', "$!adminMsg.get('xe.pagination.results.of')") -$jsonBuilder.addStringProperty('results', "$!adminMsg.get('xe.pagination.results')") -$jsonBuilder.closeDictionary() -## xwiki/usersandgroups.js -$jsonBuilder.openProperty('usersandgroups') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('denyrightforcurrentuser', "$!adminMsg.get('rightsmanager.denyrightforcurrentuser')") -$jsonBuilder.addStringProperty('clearrightforcurrentuserinstead', "$!adminMsg.get('rightsmanager.clearrightforcurrentuserinstead')") -$jsonBuilder.addStringProperty('clearrightforcurrentuser', "$!adminMsg.get('rightsmanager.clearrightforcurrentuser')") -$jsonBuilder.addStringProperty('denyrightforgroup', "$!adminMsg.get('rightsmanager.denyrightforgroup')") -$jsonBuilder.addStringProperty('clearrightforgroupinstead', "$!adminMsg.get('rightsmanager.clearrightforgroupinstead')") -$jsonBuilder.addStringProperty('clearrightforgroup', "$!adminMsg.get('rightsmanager.clearrightforgroup')") -$jsonBuilder.addStringProperty('denyrightforuorg', "$!adminMsg.get('rightsmanager.denyrightforuorg')") -$jsonBuilder.addStringProperty('clearrightforuorg', "$!adminMsg.get('rightsmanager.clearrightforuorg')") -$jsonBuilder.addStringProperty('saveFailure', "$!adminMsg.get('platform.core.rightsManagement.saveFailure')") -$jsonBuilder.addStringProperty('ajaxFailure', "$!adminMsg.get('platform.core.rightsManagement.ajaxFailure')") -$jsonBuilder.addStringProperty('edit', "$!adminMsg.get('edit')") -$jsonBuilder.addStringProperty('delete', "$!adminMsg.get('delete')") -$jsonBuilder.addStringProperty('confirmdeleteuser', "$!adminMsg.get('rightsmanager.confirmdeleteuser')") -$jsonBuilder.addStringProperty('confirmdeletegroup', "$!adminMsg.get('rightsmanager.confirmdeletegroup')") -$jsonBuilder.addStringProperty('confirmdeletemember', "$!adminMsg.get('rightsmanager.confirmdeletemember')") -$jsonBuilder.closeDictionary() -## xwiki.js -$jsonBuilder.openProperty('xwiki') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('readTechnicalInformation', "$!adminMsg.get('platform.core.rendering.error.readTechnicalInformation')") -$jsonBuilder.addStringProperty('edit', "$!adminMsg.get('edit')") -$jsonBuilder.addStringProperty('createAjaxError', "$!adminMsg.get('core.create.ajax.error')") -$jsonBuilder.closeDictionary() -## xwikiexplorer.js -$jsonBuilder.openProperty('xwikiexplorer') -$jsonBuilder.openDictionary() -$jsonBuilder.addStringProperty('attachmentsTitle', "$!adminMsg.get('xwikiexplorer.attachments.title')") -$jsonBuilder.addStringProperty('addPageTitle', "$!adminMsg.get('xwikiexplorer.addpage.title')") -$jsonBuilder.addStringProperty('addAttachmentTitle', "$!adminMsg.get('xwikiexplorer.addattachment.title')") -$jsonBuilder.closeDictionary() diff --git a/celements-webapp/src/main/webapp/templates/celMacros/CelValidationMessages.vm b/celements-webapp/src/main/webapp/templates/celMacros/CelValidationMessages.vm deleted file mode 100644 index 87de92f16..000000000 --- a/celements-webapp/src/main/webapp/templates/celMacros/CelValidationMessages.vm +++ /dev/null @@ -1,19 +0,0 @@ -$jsonBuilder.addStringProperty('language', "$language") -$jsonBuilder.addStringProperty('admin-language', "$admin_language") -$jsonBuilder.addStringProperty('required', "$adminMsg.get('cel_form_valid_required')") -$jsonBuilder.addStringProperty('validate-dateRange', "$!adminMsg.get('cel_valid_dateRange', ['', ''])") -$jsonBuilder.addStringProperty('validate-warning-header', "$!adminMsg.get('cel_tm_saving_dialog_warning_header')") -$jsonBuilder.addStringProperty('validate-blog-dateRange', "$!adminMsg.get('cel_valid_blog_dateRange', ['', ''])") -$jsonBuilder.addStringProperty('validate-number', "Please enter a valid number in this field.") -$jsonBuilder.addStringProperty('validate-digits', "Please use numbers only in this field. please avoid spaces or other characters such as dots or commas.") -$jsonBuilder.addStringProperty('validate-alpha', "Please use letters only (a-z) in this field.") -$jsonBuilder.addStringProperty('validate-alphanum', "Please use only letters (a-z) or numbers (0-9) only in this field. No spaces or other characters are allowed.") -$jsonBuilder.addStringProperty('validate-date', "Please enter a valid date.") -$jsonBuilder.addStringProperty('validate-email', "Please enter a valid email address. For example fred@domain.com .") -$jsonBuilder.addStringProperty('validate-url', "Please enter a valid URL.") -$jsonBuilder.addStringProperty('validate-date-au', "Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.") -$jsonBuilder.addStringProperty('validate-currency-dollar', 'Please enter a valid $ amount. For example $100.00 .') -$jsonBuilder.addStringProperty('validate-selection', 'Please make a selection') -$jsonBuilder.addStringProperty('validate-one-required', 'Please select one of the above options.') -$jsonBuilder.addStringProperty('validate-email-equal', "$!adminMsg.get('cel_form_valid_email-equal')") -$jsonBuilder.addStringProperty('validate-docname', "$adminMsg.get('cel_tm_validate_warning')") diff --git a/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm b/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm index a0e8be53e..487f756fe 100644 --- a/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm +++ b/celements-webapp/src/main/webapp/templates/celMacros/startCelementsDocument.vm @@ -29,7 +29,5 @@ #end #if($!withoutDefaultHeaders == false) - - #template("celMacros/includeDefaultHeader.vm") #end diff --git a/celements-webapp/src/main/webapp/templates/htmlheader.vm b/celements-webapp/src/main/webapp/templates/htmlheader.vm index 9a87dcbad..3c18efdcd 100644 --- a/celements-webapp/src/main/webapp/templates/htmlheader.vm +++ b/celements-webapp/src/main/webapp/templates/htmlheader.vm @@ -68,8 +68,6 @@ - - ## --------------------------------------------------------------------------------------------------------------- ## Localize GWT applications. ## --------------------------------------------------------------------------------------------------------------- diff --git a/component/pom.xml b/component/pom.xml deleted file mode 100644 index c242eb4dd..000000000 --- a/component/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - com.celements - celements-parent - 7.1-SNAPSHOT - - 4.0.0 - https://github.com/celements/celements-web - celements-web-component - 7.1-SNAPSHOT - Celements Web Component - - - com.celements - celements-model - provided - - - com.celements - celements-spring-security - provided - - - com.celements - celements-xwiki-core - provided - - - com.celements - celements-observation - provided - - - com.celements - celements-xwiki-velocity - provided - - - com.celements - celements-core - provided - - - org.springframework - spring-context - provided - - - org.springframework - spring-web - provided - - - org.springframework - spring-webmvc - provided - - - javax.inject - javax.inject - - - javax.servlet - javax.servlet-api - provided - - - com.celements - celements-shared-tests - test - - - - scm:git:git://github.com/celements/celements-web - scm:git:git@github.com:celements/celements-web.git - https://github.com/celements/celements-web - HEAD - - diff --git a/component/src/main/java/com/celements/web/api/MessagesController.java b/component/src/main/java/com/celements/web/api/MessagesController.java deleted file mode 100644 index 115ec2909..000000000 --- a/component/src/main/java/com/celements/web/api/MessagesController.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.celements.web.api; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; - -import javax.inject.Inject; -import javax.servlet.ServletContext; - -import org.apache.velocity.VelocityContext; -import org.springframework.http.MediaType; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xwiki.velocity.VelocityManager; -import org.xwiki.velocity.XWikiVelocityException; - -import com.celements.spring.security.AuthenticatedBaseController; -import com.celements.web.service.IPrepareVelocityContext; - -@RestController -@RequestMapping("/v1/messages") -@PreAuthorize("permitAll()") -public class MessagesController extends AuthenticatedBaseController { - - private final ServletContext servletContext; - - private final VelocityManager velocityManager; - - private final IPrepareVelocityContext prepareVelocityContext; - - @Inject - public MessagesController(ServletContext servletContext, VelocityManager velocityManager, - IPrepareVelocityContext prepareVelocityContext) { - this.servletContext = servletContext; - this.velocityManager = velocityManager; - this.prepareVelocityContext = prepareVelocityContext; - } - - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8") - public String getMessages() throws IOException, XWikiVelocityException { - return renderTemplate("/templates/celAjax/Messages.vm"); - } - - @GetMapping(value = "/validation", produces = MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8") - public String getValidationMessages() throws IOException, XWikiVelocityException { - return renderTemplate("/templates/celAjax/ValidationMessages.vm"); - } - - private String renderTemplate(String template) throws IOException, XWikiVelocityException { - checkAuth(); - VelocityContext velocityContext = velocityManager.getVelocityContext(); - prepareVelocityContext.prepareVelocityContext(velocityContext); - var writer = new StringWriter(); - velocityManager.getVelocityEngine().evaluate(velocityContext, writer, template, - getTemplateContent(template)); - return writer.toString().trim(); - } - - private String getTemplateContent(String template) throws IOException { - try (InputStream stream = servletContext.getResourceAsStream(template)) { - if (stream == null) { - throw new IOException("Template not found: " + template); - } - return new String(stream.readAllBytes(), StandardCharsets.UTF_8); - } - } -} diff --git a/component/src/test/java/com/celements/web/api/MessagesControllerTest.java b/component/src/test/java/com/celements/web/api/MessagesControllerTest.java deleted file mode 100644 index 66fc43ac0..000000000 --- a/component/src/test/java/com/celements/web/api/MessagesControllerTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.celements.web.api; - -import static org.easymock.EasyMock.*; -import static org.junit.Assert.*; - -import java.io.ByteArrayInputStream; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.Optional; - -import javax.servlet.ServletContext; - -import org.apache.velocity.VelocityContext; -import org.junit.Before; -import org.junit.Test; -import org.xwiki.velocity.VelocityEngine; -import org.xwiki.velocity.VelocityManager; - -import com.celements.auth.user.User; -import com.celements.web.service.IPrepareVelocityContext; - -public class MessagesControllerTest { - - private ServletContext servletContext; - - private VelocityManager velocityManager; - - private IPrepareVelocityContext prepareVelocityContext; - - private MessagesController controller; - - @Before - public void prepareTest() { - servletContext = createMock(ServletContext.class); - velocityManager = createMock(VelocityManager.class); - prepareVelocityContext = createMock(IPrepareVelocityContext.class); - controller = new TestMessagesController(servletContext, velocityManager, prepareVelocityContext); - } - - @Test - public void test_getMessages_rendersGeneralTemplateWithRequestVelocityContext() throws Exception { - var velocityEngine = expectTemplateRendering("/templates/celAjax/Messages.vm", - " {\"message\":true} "); - replay(servletContext, velocityManager, prepareVelocityContext, velocityEngine); - assertEquals("{\"message\":true}", controller.getMessages()); - assertTrue(((TestMessagesController) controller).isCheckAuthCalled()); - verify(servletContext, velocityManager, prepareVelocityContext, velocityEngine); - } - - @Test - public void test_getValidationMessages_rendersValidationTemplateWithRequestVelocityContext() - throws Exception { - var velocityEngine = expectTemplateRendering("/templates/celAjax/ValidationMessages.vm", - " {\"required\":true} "); - replay(servletContext, velocityManager, prepareVelocityContext, velocityEngine); - assertEquals("{\"required\":true}", controller.getValidationMessages()); - assertTrue(((TestMessagesController) controller).isCheckAuthCalled()); - verify(servletContext, velocityManager, prepareVelocityContext, velocityEngine); - } - - private VelocityEngine expectTemplateRendering(String template, String renderedTemplate) - throws Exception { - var velocityContext = new VelocityContext(); - VelocityEngine velocityEngine = createMock(VelocityEngine.class); - expect(velocityManager.getVelocityContext()).andReturn(velocityContext); - prepareVelocityContext.prepareVelocityContext(velocityContext); - expect(velocityManager.getVelocityEngine()).andReturn(velocityEngine); - expect(servletContext.getResourceAsStream(template)).andReturn( - new ByteArrayInputStream("template".getBytes(StandardCharsets.UTF_8))); - expect(velocityEngine.evaluate(same(velocityContext), isA(StringWriter.class), eq(template), - eq("template"))).andAnswer(() -> { - ((StringWriter) getCurrentArguments()[1]).write(renderedTemplate); - return true; - }); - return velocityEngine; - } - - private static final class TestMessagesController extends MessagesController { - - private boolean checkAuthCalled; - - TestMessagesController(ServletContext servletContext, VelocityManager velocityManager, - IPrepareVelocityContext prepareVelocityContext) { - super(servletContext, velocityManager, prepareVelocityContext); - } - - @Override - protected Optional checkAuth() { - checkAuthCalled = true; - return Optional.empty(); - } - - boolean isCheckAuthCalled() { - return checkAuthCalled; - } - } -}