diff --git a/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js b/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js index 04d1d0b07553..67b1f3b3103c 100644 --- a/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js +++ b/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js @@ -12,7 +12,7 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(t,e,n){"use strict";class i{textarea;remainder=null;constructor(t){if(this.textarea=document.getElementById(t),null===this.textarea)throw new Error(`Could not find textarea for input-id '${t}'.`);if(this.shouldShowRemainder()){if(this.remainder=this.textarea.parentNode.querySelector('[data-action="remainder"]'),!this.remainder instanceof HTMLSpanElement)throw new Error(`Could not find remainder-element for input-id '${t}'.`);this.textarea.addEventListener("input",(()=>{this.updateRemainderCountHook()}))}}updateRemainderCountHook(){this.shouldShowRemainder()&&null!==this.remainder&&(this.remainder.innerHTML=(this.textarea.maxLength-this.textarea.value.length).toString())}updateTextareaContent(t,e=null,n=null){if(!this.isDisabled()){if(this.isContentTooLarge(t))return this.updateRemainderCountHook(),void this.textarea.focus();e=e??this.textarea.selectionStart,n=n??this.textarea.selectionEnd,this.textarea.value=t,ethis.textarea.selectionEnd?this.textarea.selectionStart:this.textarea.selectionEnd}getLinesBeforeSelection(){return a(this.textarea.value).slice(0,s(this.getTextBeforeSelection()))}getLinesAfterSelection(){const t=a(this.textarea.value);return t.slice(s(this.getTextBeforeSelection()+this.getTextOfSelection())+1,t.length)}getLinesOfSelection(){const t=a(this.textarea.value);return t.slice(this.getLinesBeforeSelection().length,t.length-this.getLinesAfterSelection().length)}isContentTooLarge(t){const e=this.getMaxLength();return!(e<0)&&e0}getMaxLength(){return Number(this.textarea.getAttribute("maxlength")??-1)}isDisabled(){return this.textarea.disabled}}function s(t){return(t.match(/\n/g)??[]).length}function a(t){return t.split(/\n/)}class o{instances=[];init(t){if(void 0!==this.instances[t])throw new Error(`Textarea with input-id '${t}' has already been initialized.`);this.instances[t]=new i(t)}get(t){return this.instances[t]??null}}class r{preview_parameter;preview_url;constructor(t,e){this.preview_parameter=t,this.preview_url=e}async getPreviewHtmlOf(t){if(0===t.length)return"";let e=new FormData;return e.append(this.preview_parameter,t),(await fetch(this.preview_url,{method:"POST",body:e})).text()}}const l="textarea",d="preview";class c extends i{preview_history=[];preview_renderer;content_wrappers;view_controls;actions;constructor(t,e){super(e);const n=this.textarea.closest(".c-field-markdown");if(null===n)throw new Error(`Could not find input-wrapper for input-id '${e}'.`);this.preview_renderer=t,this.content_wrappers=function(t){const e=new Map;return e.set(l,t.querySelector("textarea")),e.set(d,t.querySelector(".c-field-markdown__preview")),e.forEach((t=>{if(null===t)throw new Error("Could not find all content-wrappers for markdown-input.")})),e}(n),this.view_controls=function(t){const e=t.querySelector(".il-viewcontrol-mode")?.getElementsByTagName("button");if(!e instanceof HTMLCollection||2!==e.length)throw new Error("Could not find exactly two view-controls.");return[...e]}(n),this.actions=function(t){const e=t.querySelector(".c-field-markdown__actions")?.getElementsByTagName("button");if(e instanceof HTMLCollection)return[...e];return[]}(n);let i=!0;this.textarea.addEventListener("keydown",(t=>{i=this.handleEnterKeyBeforeInsertionHook(t)})),this.textarea.addEventListener("keyup",(t=>{this.handleEnterKeyAfterInsertionHook(t,i)})),this.actions.forEach((t=>{t.addEventListener("click",(t=>{this.performMarkdownActionHook(t)}))})),this.view_controls.forEach((t=>{t.addEventListener("click",(()=>{this.toggleViewingModeHook()}))}))}handleEnterKeyAfterInsertionHook(t,e){if(!e||!p(t))return;const n=this.getLinesBeforeSelection().pop();void 0!==n&&m(n)?this.applyTransformationToSelection(u):void 0!==n&&v(n)&&this.insertSingleEnumeration()}handleEnterKeyBeforeInsertionHook(t){if(!p(t))return!1;const e=this.getLinesOfSelection().shift();if(void 0===e||!((e.match(/((^(\s*-)|(^(\s*\d+\.)))\s*)$/g)??[]).length>0))return!0;let n=this.getLinesBeforeSelection().join("\n"),i=this.getLinesAfterSelection().join("\n");return n.length>0&&(n+="\n"),i.length>0&&(i=`\n${i}`),this.updateTextareaContent(n+i,this.getAbsoluteSelectionStart()-e.length,this.getAbsoluteSelectionEnd()-e.length),t.preventDefault(),!1}performMarkdownActionHook(t){const e=function(t){const e=t.closest("span[data-action]");if(!e instanceof HTMLSpanElement)return null;if(!e.hasAttribute("data-action"))return null;return e.dataset.action}(t.target);switch(e){case"insert-heading":this.insertCharactersAroundSelection("# ","");break;case"insert-link":this.insertCharactersAroundSelection("[","](url)");break;case"insert-bold":this.insertCharactersAroundSelection("**","**");break;case"insert-italic":this.insertCharactersAroundSelection("_","_");break;case"insert-bullet-points":this.applyTransformationToSelection(u);break;case"insert-enumeration":this.isMultilineTextSelected()?this.applyTransformationToSelection(h):this.insertSingleEnumeration();break;default:throw new Error(`Could not perform markdown-action '${e}'.`)}}toggleViewingModeHook(){this.content_wrappers.forEach((t=>{g(t,"hidden")})),this.view_controls.forEach((t=>{g(t,"engaged")})),this.isDisabled()||this.actions.forEach((t=>{t.disabled=!t.disabled;const e=t.querySelector(".glyph");null!==e&&g(e,"disabled")})),this.maybeUpdatePreviewContent()}insertSingleEnumeration(){const t=this.getLinesOfSelection();if(1!==t.length)return void this.textarea.focus();const e=this.getLinesBeforeSelection(),n=e.length-1;let i=n>=0?function(t){const e=t.match(/([0-9]+)/);if(null!==e)return parseInt(e[0]);return null}(e[n])??0:0;const s=h(t,++i),a=function(t,e=0){if(t.length<1)return[];const n=[];for(const i of t){if(!v(i))break;n.push(i.replace(/([0-9]+)/,(++e).toString()))}n.length>0&&(t=n.concat(t.slice(n.length)));return t}(this.getLinesAfterSelection(),i);let o=e.join("\n");const r=a.join("\n");let l=s.join("\n");o.length>0&&l.length>0&&(o+="\n"),l.length>0&&r.length>0&&(l+="\n");const d=o+l+r,c=d.length-this.textarea.value.length;this.updateTextareaContent(d,this.getAbsoluteSelectionStart()+c,this.getAbsoluteSelectionEnd()+c)}applyTransformationToSelection(t){if(!t instanceof Function)throw new Error(`Transformation must be an instance of Function, ${typeof t} given.`);const e=t(this.getLinesOfSelection());if(!e instanceof Array)throw new Error(`Transformation must return an instance of Array, ${typeof e} returned.`);const n=e.length>1;let i=this.getLinesBeforeSelection().join("\n");const s=this.getLinesAfterSelection().join("\n");let a=e.join("\n");i.length>0&&a.length>0&&(i+="\n"),a.length>0&&s.length>0&&(a+="\n");const o=i+a+s,r=o.length-this.textarea.value.length,l=n?i.length:this.getAbsoluteSelectionStart()+r,d=n?l+a.length-1:this.getAbsoluteSelectionEnd()+r;this.updateTextareaContent(o,l,d)}maybeUpdatePreviewContent(){const t=this.preview_history[this.preview_history.length-1]??"",e=this.textarea.value;e!==t&&(this.preview_history.push(e),this.preview_renderer.getPreviewHtmlOf(e).then((t=>{this.content_wrappers.get(d).innerHTML=t})))}getBulletPointTransformation(){return u}getEnumerationTransformation(){return h}}function u(t){const e=[],n=!m(t[0]??"");for(const i of t)e.push(n?`- ${i}`:f(i));return e}function h(t,e=1){const n=[],i=!v(t[0]??"");for(const s of t)n.push(i?`${e++}. ${s}`:f(s));return n}function g(t,e){t.classList.contains(e)?t.classList.remove(e):t.classList.add(e)}function p(t){return t instanceof KeyboardEvent&&"Enter"===t.code}function f(t){return t.replace(/((^(\s*[-])|(^(\s*\d+\.)))\s*)/g,"")}function m(t){return(t.match(/^(\s*[-])/g)??[]).length>0}function v(t){return(t.match(/^(\s*\d+\.)/g)??[]).length>0}class w{instances=[];init(t,e,n){if(void 0!==this.instances[t])throw new Error(`Markdown with input-id '${t}' has already been initialized.`);this.instances[t]=new c(new r(n,e),t)}get(t){return this.instances[t]??null}}class y{constructor(t,e,n,i,s,a=null,o=null,r=null){this.id=t,this.name=e,this.element=n,this.selectButton=i,this.drilldownParentLevel=s,this.drilldownButton=a,this.listElement=o,this.renderUrl=r}}const b="data-node-id",T="data-node-name",S="data-render-url",x="data-ddindex",E="c-input-node",O="c-input-tree_select",D=`${E}__async`,C=`${E}__leaf`,I=`${E}--selected`,A="hidden",M="disabled",N=".glyph",_=`.${E}`,L=`.${O}`,k=`.${O}__selection`,P='[data-action="remove"]',B='[data-action="select"]',j=`.${E}__select`,V=".c-drilldown__menulevel--trigger";function F(t){return function(t){return t.classList.contains(D)}(t)&&t.hasAttribute(S)?t.getAttribute(S):null}function H(t){return!t.classList.contains(C)&&t.classList.contains(E)}function q(t,e=null){return t.reduce(((t,e)=>{const n=function(t){const e=t.getAttribute(b);if(null===e)throw new Error("Could not find data-node-id attribute.");return e}(e);if(t.has(n))throw new Error(`Node '${n}' has already been parsed. There might be a rendering issue.`);return t.set(n,new y(n,function(t){const e=t.querySelector(`[${T}]`);if(null===e)throw new Error("Could not find element with data-node-name attribute.");return e.textContent}(e),e,function(t){const e=t.querySelector(`:scope > ${j}`);if(null===e)throw new Error("Could not find node select button.");return e}(e),function(t){const e=t.closest(`ul[${x}]`);if(null===e)throw new Error("Could not find drilldown menu of node.");return e.getAttribute(x)}(e),function(t){if(!H(t))return null;const e=t.querySelector(`${V}`);if(null===e)throw new Error("Could not find drilldown menu button of branch node.");return e}(e),function(t){if(!H(t))return null;const e=t.querySelector("ul");if(null===e)throw new Error("Could not find list element of branch node.");return e}(e),F(e)))}),new Map(e??[]))}function R(t,e){for(let n=0;nn.shift()??""))}function U(t,e){t.classList.toggle(I,e)}class W{#t;#e=new Set;#n=new Set;#i=new Set;#s;#a;#o;#r;#l;#d;#c;#u;#h;#g;#p;#f;constructor(t,e,n,i,s,a,o,r,l,d,c,u,h,g){this.#t=t,this.#s=n,this.#a=i,this.#o=s,this.#r=a,this.#l=o,this.#d=r,this.#c=l,this.#u=d,this.#h=c,this.#g=u,this.#p=h,this.#f=g,e.on(this.#p.ownerDocument,this.#r.getBackSignal(),(()=>{this.#m()})),this.#p.querySelectorAll('[data-action="close"]').forEach((t=>{t.addEventListener("click",(()=>{this.#v()}))})),this.#r.addEngageListener((t=>{this.#w(t)})),this.#g.addEventListener("click",(()=>{this.#y()})),this.#t.forEach((t=>{this.#b(t)})),this.#c.querySelectorAll("li").forEach((t=>{const e=function(t){const e=t.getAttribute(b);if(null===e)throw new Error(`Could not find '${b}' attribbute of element.`);return e}(t);this.#T(t,e),this.selectNode(e)})),this.#w(this.#r.getCurrentLevel()),this.#S()}unselectNode(t){if(this.#x(t),this.#S(),this.#E(t),this.#t.has(t)){const e=this.#t.get(t);U(e.element,!1),this.#O(e.selectButton,e.name)}this.#f(this)}selectNode(t){if(this.#D(t),this.#S(),this.#t.has(t)){const e=this.#t.get(t);U(e.element,!0),this.#C(e.selectButton,e.name),this.#I(e)}this.#f(this)}engageNode(t){if(!this.#t.has(t))return;const e=this.#t.get(t).drilldownParentLevel;this.#r.getCurrentLevel()!==e&&this.#r.getParentLevel()!==e&&this.#r.engageLevel(e)}getSelection(){return new Set(this.#e)}getNodes(){return new Map(this.#t)}async#A(t){var e,n,i;if(!this.#n.has(t.id)&&!this.#i.has(t.id))try{this.#i.add(t.id);const s=await this.#a.loadContent(t.renderUrl);t.listElement.append(...s.children),this.#r.parseLevels();const a=q((i=t.listElement,Array.from(i.querySelectorAll(_))),this.#t),o=(e=a,n=this.#t,Array.from(e.entries()).filter((([t])=>!n.has(t))).map((([,t])=>t)));this.#t=a,R(o,(t=>{this.#e.has(t.id)?this.selectNode(t.id):this.unselectNode(t.id),this.#b(t)})),this.#n.add(t.id)}catch(t){throw new Error(`Could not render async node children: ${t.message}`)}finally{this.#i.delete(t.id)}}#M(t){R(function(t,e,n=255){const i=[];let s=t;for(let t=0;t{const e=t.getAttribute(b);if(null===e||!this.#t.has(e))throw new Error(`Could not find '${b}' of node element.`);const n=this.#t.get(e);this.#N(n)}))}#N(t){const e=this.#s.createContent(this.#d).querySelector(".crumb");e.setAttribute(x,t.drilldownParentLevel),e.firstElementChild.textContent=t.name,e.addEventListener("click",(()=>{this.#r.engageLevel(t.drilldownParentLevel),t.drilldownButton.click()})),this.#l.append(e)}#m(){const t=this.#l.querySelectorAll(".crumb");t.item(t.length-1)?.remove()}#_(){R(this.#l.querySelectorAll(".crumb"),(t=>{t.remove()}))}#w(t){if("0"===t)return void this.#_();const e=this.#p.querySelector(`ul[${x}="${t}"]`)?.closest(_)?.getAttribute(b);if(null===e||!this.#t.has(e))throw new Error(`Could not find node for drilldown-level '${t}'.`);const n=this.#t.get(e);this.#_(),this.#M(n),null!==n.renderUrl&&this.#A(n)}#T(t,e){t.querySelector(P)?.addEventListener("click",(()=>{this.unselectNode(e),t.remove()}))}#L(t,e){t.addEventListener("click",(()=>{this.#e.has(e.id)?this.unselectNode(e.id):this.selectNode(e.id)}))}#I(t){if(null!==this.#c.querySelector(`li[${b}="${t.id}"]`))return;const e=this.#s.createContent(this.#u),n=e.querySelector("[data-node-id]");n.setAttribute(b,t.id),n.querySelector(`[${T}]`).textContent=t.name,n.querySelector("input").value=t.id,this.#T(n,t.id),this.#c.append(...e.children)}#E(t){this.#c.querySelector(`li[${b}="${t}"]`)?.remove()}#b(t){this.#L(t.selectButton,t)}#O(t,e){t.querySelector(P)?.classList.add(A),t.querySelector(B)?.classList.remove(A),t.setAttribute("aria-label",this.#k("select_node",e))}#C(t,e){t.querySelector(B)?.classList.add(A),t.querySelector(P)?.classList.remove(A),t.setAttribute("aria-label",this.#k("unselect_node",e))}#S(){this.#h.disabled=this.#e.size<=0}#x(t){this.#e.has(t)&&this.#e.delete(t)}#D(t){this.#e.has(t)||this.#e.add(t)}#k(t,...e){return $(this.#o.txt(t),e)}#v(){this.#p.close()}#y(){this.#p.showModal()}}function z(t,e){const n=t.createDocumentFragment();return n.append(...e),n}function K(t,e,n){t.querySelectorAll(`[${n}]`).forEach((t=>{const i=t.getAttribute(n);if(!e.has(i))throw new Error(`Element references '${i}' which does not exist.`);t.setAttribute(n,e.get(i))}))}class X{#P;constructor(t){this.#P=t}createContent(t){const e=t.content.cloneNode(!0),n=new Map;return e.querySelectorAll("[id]").forEach((t=>{const e=function(t=""){return`${t}${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`}("il_ui_fw_");n.set(t.id,e),t.id=e})),e.querySelectorAll("[for]").forEach((t=>{t.htmlFor=n.get(t.htmlFor)})),K(e,n,"aria-describedby"),K(e,n,"aria-labelledby"),K(e,n,"aria-controls"),K(e,n,"aria-owns"),z(this.#P,e.children)}}class J{#P;constructor(t){this.#P=t}loadContent(t){return fetch(t.toString()).then((t=>t.text())).then((t=>this.#B(t))).then((t=>z(this.#P,t))).catch((e=>{throw new Error(`Could not render element(s) from '${t}': ${e.message}`)}))}#j(t){const e=this.#P.createElement("script");return t.hasAttribute("type")&&e.setAttribute("type",t.getAttribute("type")),t.hasAttribute("src")&&e.setAttribute("src",t.getAttribute("src")),t.textContent.length>0&&(e.textContent=t.textContent),e}#B(t){const e=this.#P.createElement("div");return e.innerHTML=t.trim(),e.querySelectorAll("script").forEach((t=>{const e=this.#j(t);t.replaceWith(e)})),e.children}}function Q(t){return Array.from(t.querySelectorAll(_))}function G(){return t=>{!function(t){const e=t.getNodes(),n=t.getSelection();e.forEach(((t,e)=>{n.size>0?(t.selectButton.disabled=!n.has(e),t.selectButton.querySelector(N).classList.toggle(M,!n.has(e))):(t.selectButton.disabled=!1,t.selectButton.querySelector(N).classList.toggle(M,!1))}))}(t),function(t){const e=t.getSelection();if(1===e.size){const n=e.values()?.next()?.value;t.getNodes().has(n)&&t.engageNode(n)}}(t)}}function Y(t){return t?()=>{}:t=>{!function(t){const e=Array.from(t.getSelection()),n=t.getNodes();for(let s=0;s{t.selectButton.disabled=!1,t.selectButton.querySelector(N).classList.remove(M)})),n.forEach((t=>{const n=e.get(t);null!==n&&null!==n.listElement&&n.listElement.querySelectorAll(j).forEach((t=>{t.disabled=!0,t.querySelector(N).classList.add(M)}))}))}(t)}}class Z{#V=new Map;#F;#H;#o;#P;constructor(t,e,n,i){this.#F=t,this.#H=e,this.#o=n,this.#P=i}initTreeMultiSelect(t,e){if(this.#V.has(t))throw new Error(`TreeSelect '${t}' already exists.`);const[n,i,s,a,o,r,l,d]=this.#q(t),c=this.#R(i),u=new W(q(Q(l)),this.#F,new X(this.#P),new J(this.#P),this.#o,c,s,a,o,r,d,n,l,Y(e));return this.#V.set(t,u),u}initTreeSelect(t){if(this.#V.has(t))throw new Error(`TreeSelect '${t}' already exists.`);const[e,n,i,s,a,o,r,l]=this.#q(t),d=this.#R(n),c=new W(q(Q(r)),this.#F,new X(this.#P),new J(this.#P),this.#o,d,i,s,a,o,l,e,r,G());return this.#V.set(t,c),c}getInstance(t){return this.#V.has(t)?this.#V.get(t):null}#q(t){const e=this.#P.getElementById(t),n=e?.closest(L),i=n?.querySelector(".breadcrumb"),s=n?.querySelector(".modal-body > template"),a=n?.querySelector(k),o=a?.querySelector(":scope > template"),r=n?.querySelector("dialog"),l=r?.querySelector(".btn-primary");if(null===i||null===s||null===a||null===o||null===l||null===e||null===r)throw new Error(`Could not find some element(s) for Tree Select Input '${t}'.`);return[e,n,i,s,a,o,r,l]}#R(t){const e=t.querySelector(".c-drilldown");if(null===e||!e.hasAttribute("id"))throw new Error("Could not find drilldown element.");const n=this.#H.getInstance(e.id);if(null===e)throw new Error("Could not find drilldown instance.");return n}}class tt{#$;constructor(t){this.#$=t}on(t,e,n){this.#$(t).on(e,n)}off(t,e,n){this.#$(t).off(e,n)}} +!function(t,e,n){"use strict";class i{textarea;remainder=null;constructor(t){if(this.textarea=document.getElementById(t),null===this.textarea)throw new Error(`Could not find textarea for input-id '${t}'.`);if(this.shouldShowRemainder()){if(this.remainder=this.textarea.parentNode.querySelector('[data-action="remainder"]'),!this.remainder instanceof HTMLSpanElement)throw new Error(`Could not find remainder-element for input-id '${t}'.`);this.textarea.addEventListener("input",(()=>{this.updateRemainderCountHook()}))}}updateRemainderCountHook(){this.shouldShowRemainder()&&null!==this.remainder&&(this.remainder.innerHTML=(this.textarea.maxLength-this.textarea.value.length).toString())}updateTextareaContent(t,e=null,n=null){if(!this.isDisabled()){if(this.isContentTooLarge(t))return this.updateRemainderCountHook(),void this.textarea.focus();e=e??this.textarea.selectionStart,n=n??this.textarea.selectionEnd,this.textarea.value=t,ethis.textarea.selectionEnd?this.textarea.selectionStart:this.textarea.selectionEnd}getLinesBeforeSelection(){return a(this.textarea.value).slice(0,s(this.getTextBeforeSelection()))}getLinesAfterSelection(){const t=a(this.textarea.value);return t.slice(s(this.getTextBeforeSelection()+this.getTextOfSelection())+1,t.length)}getLinesOfSelection(){const t=a(this.textarea.value);return t.slice(this.getLinesBeforeSelection().length,t.length-this.getLinesAfterSelection().length)}isContentTooLarge(t){const e=this.getMaxLength();return!(e<0)&&e0}getMaxLength(){return Number(this.textarea.getAttribute("maxlength")??-1)}isDisabled(){return this.textarea.disabled}}function s(t){return(t.match(/\n/g)??[]).length}function a(t){return t.split(/\n/)}class o{instances=[];init(t){if(void 0!==this.instances[t])throw new Error(`Textarea with input-id '${t}' has already been initialized.`);this.instances[t]=new i(t)}get(t){return this.instances[t]??null}}class r{preview_parameter;preview_url;constructor(t,e){this.preview_parameter=t,this.preview_url=e}async getPreviewHtmlOf(t){if(0===t.length)return"";let e=new FormData;return e.append(this.preview_parameter,t),(await fetch(this.preview_url,{method:"POST",body:e})).text()}}const l="textarea",d="preview";class c extends i{preview_history=[];preview_renderer;content_wrappers;view_controls;actions;constructor(t,e){super(e);const n=this.textarea.closest(".c-field-markdown");if(null===n)throw new Error(`Could not find input-wrapper for input-id '${e}'.`);this.preview_renderer=t,this.content_wrappers=function(t){const e=new Map;return e.set(l,t.querySelector("textarea")),e.set(d,t.querySelector(".c-field-markdown__preview")),e.forEach((t=>{if(null===t)throw new Error("Could not find all content-wrappers for markdown-input.")})),e}(n),this.view_controls=function(t){const e=t.querySelector(".il-viewcontrol-mode")?.getElementsByTagName("button");if(!e instanceof HTMLCollection||2!==e.length)throw new Error("Could not find exactly two view-controls.");return[...e]}(n),this.actions=function(t){const e=t.querySelector(".c-field-markdown__actions")?.getElementsByTagName("button");if(e instanceof HTMLCollection)return[...e];return[]}(n);let i=!0;this.textarea.addEventListener("keydown",(t=>{i=this.handleEnterKeyBeforeInsertionHook(t)})),this.textarea.addEventListener("keyup",(t=>{this.handleEnterKeyAfterInsertionHook(t,i)})),this.actions.forEach((t=>{t.addEventListener("click",(t=>{this.performMarkdownActionHook(t)}))})),this.view_controls.forEach((t=>{t.addEventListener("click",(()=>{this.toggleViewingModeHook()}))}))}handleEnterKeyAfterInsertionHook(t,e){if(!e||!p(t))return;const n=this.getLinesBeforeSelection().pop();void 0!==n&&m(n)?this.applyTransformationToSelection(u):void 0!==n&&v(n)&&this.insertSingleEnumeration()}handleEnterKeyBeforeInsertionHook(t){if(!p(t))return!1;const e=this.getLinesOfSelection().shift();if(void 0===e||!((e.match(/((^(\s*-)|(^(\s*\d+\.)))\s*)$/g)??[]).length>0))return!0;let n=this.getLinesBeforeSelection().join("\n"),i=this.getLinesAfterSelection().join("\n");return n.length>0&&(n+="\n"),i.length>0&&(i=`\n${i}`),this.updateTextareaContent(n+i,this.getAbsoluteSelectionStart()-e.length,this.getAbsoluteSelectionEnd()-e.length),t.preventDefault(),!1}performMarkdownActionHook(t){const e=function(t){const e=t.closest("span[data-action]");if(!e instanceof HTMLSpanElement)return null;if(!e.hasAttribute("data-action"))return null;return e.dataset.action}(t.target);switch(e){case"insert-heading":this.insertCharactersAroundSelection("# ","");break;case"insert-link":this.insertCharactersAroundSelection("[","](url)");break;case"insert-bold":this.insertCharactersAroundSelection("**","**");break;case"insert-italic":this.insertCharactersAroundSelection("_","_");break;case"insert-bullet-points":this.applyTransformationToSelection(u);break;case"insert-enumeration":this.isMultilineTextSelected()?this.applyTransformationToSelection(h):this.insertSingleEnumeration();break;default:throw new Error(`Could not perform markdown-action '${e}'.`)}}toggleViewingModeHook(){this.content_wrappers.forEach((t=>{g(t,"hidden")})),this.view_controls.forEach((t=>{g(t,"engaged")})),this.isDisabled()||this.actions.forEach((t=>{t.disabled=!t.disabled;const e=t.querySelector(".glyph");null!==e&&g(e,"disabled")})),this.maybeUpdatePreviewContent()}insertSingleEnumeration(){const t=this.getLinesOfSelection();if(1!==t.length)return void this.textarea.focus();const e=this.getLinesBeforeSelection(),n=e.length-1;let i=n>=0?function(t){const e=t.match(/([0-9]+)/);if(null!==e)return parseInt(e[0]);return null}(e[n])??0:0;const s=h(t,++i),a=function(t,e=0){if(t.length<1)return[];const n=[];for(const i of t){if(!v(i))break;n.push(i.replace(/([0-9]+)/,(++e).toString()))}n.length>0&&(t=n.concat(t.slice(n.length)));return t}(this.getLinesAfterSelection(),i);let o=e.join("\n");const r=a.join("\n");let l=s.join("\n");o.length>0&&l.length>0&&(o+="\n"),l.length>0&&r.length>0&&(l+="\n");const d=o+l+r,c=d.length-this.textarea.value.length;this.updateTextareaContent(d,this.getAbsoluteSelectionStart()+c,this.getAbsoluteSelectionEnd()+c)}applyTransformationToSelection(t){if(!t instanceof Function)throw new Error(`Transformation must be an instance of Function, ${typeof t} given.`);const e=t(this.getLinesOfSelection());if(!e instanceof Array)throw new Error(`Transformation must return an instance of Array, ${typeof e} returned.`);const n=e.length>1;let i=this.getLinesBeforeSelection().join("\n");const s=this.getLinesAfterSelection().join("\n");let a=e.join("\n");i.length>0&&a.length>0&&(i+="\n"),a.length>0&&s.length>0&&(a+="\n");const o=i+a+s,r=o.length-this.textarea.value.length,l=n?i.length:this.getAbsoluteSelectionStart()+r,d=n?l+a.length-1:this.getAbsoluteSelectionEnd()+r;this.updateTextareaContent(o,l,d)}maybeUpdatePreviewContent(){const t=this.preview_history[this.preview_history.length-1]??"",e=this.textarea.value;e!==t&&(this.preview_history.push(e),this.preview_renderer.getPreviewHtmlOf(e).then((t=>{this.content_wrappers.get(d).innerHTML=t})))}getBulletPointTransformation(){return u}getEnumerationTransformation(){return h}}function u(t){const e=[],n=!m(t[0]??"");for(const i of t)e.push(n?`- ${i}`:f(i));return e}function h(t,e=1){const n=[],i=!v(t[0]??"");for(const s of t)n.push(i?`${e++}. ${s}`:f(s));return n}function g(t,e){t.classList.contains(e)?t.classList.remove(e):t.classList.add(e)}function p(t){return t instanceof KeyboardEvent&&"Enter"===t.code}function f(t){return t.replace(/((^(\s*[-])|(^(\s*\d+\.)))\s*)/g,"")}function m(t){return(t.match(/^(\s*[-])/g)??[]).length>0}function v(t){return(t.match(/^(\s*\d+\.)/g)??[]).length>0}class w{instances=[];init(t,e,n){if(void 0!==this.instances[t])throw new Error(`Markdown with input-id '${t}' has already been initialized.`);this.instances[t]=new c(new r(n,e),t)}get(t){return this.instances[t]??null}}class y{constructor(t,e,n,i,s,a=null,o=null,r=null){this.id=t,this.name=e,this.element=n,this.selectButton=i,this.drilldownParentLevel=s,this.drilldownButton=a,this.listElement=o,this.renderUrl=r}}const b="data-node-id",T="data-node-name",S="data-render-url",x="data-ddindex",E="c-input-node",O="c-input-tree_select",D=`${E}__async`,C=`${E}__leaf`,I=`${E}--selected`,A="hidden",M="disabled",N=".glyph",_=`.${E}`,L=`.${O}`,k=`.${O}__selection`,P='[data-action="remove"]',B='[data-action="select"]',j=`.${E}__select`,V=".c-drilldown__menulevel--trigger";function F(t){return function(t){return t.classList.contains(D)}(t)&&t.hasAttribute(S)?t.getAttribute(S):null}function H(t){return!t.classList.contains(C)&&t.classList.contains(E)}function q(t,e=null){return t.reduce(((t,e)=>{const n=function(t){const e=t.getAttribute(b);if(null===e)throw new Error("Could not find data-node-id attribute.");return e}(e);if(t.has(n))throw new Error(`Node '${n}' has already been parsed. There might be a rendering issue.`);return t.set(n,new y(n,function(t){const e=t.querySelector(`[${T}]`);if(null===e)throw new Error("Could not find element with data-node-name attribute.");return e.textContent}(e),e,function(t){const e=t.querySelector(`:scope > ${j}`);if(null===e)throw new Error("Could not find node select button.");return e}(e),function(t){const e=t.closest(`ul[${x}]`);if(null===e)throw new Error("Could not find drilldown menu of node.");return e.getAttribute(x)}(e),function(t){if(!H(t))return null;const e=t.querySelector(`${V}`);if(null===e)throw new Error("Could not find drilldown menu button of branch node.");return e}(e),function(t){if(!H(t))return null;const e=t.querySelector("ul");if(null===e)throw new Error("Could not find list element of branch node.");return e}(e),F(e)))}),new Map(e??[]))}function R(t,e){for(let n=0;nn.shift()??""))}function U(t,e){t.classList.toggle(I,e)}class W{#t;#e=new Set;#n=new Set;#i=new Set;#s;#a;#o;#r;#l;#d;#c;#u;#h;#g;#p;#f;constructor(t,e,n,i,s,a,o,r,l,d,c,u,h,g){this.#t=t,this.#s=n,this.#a=i,this.#o=s,this.#r=a,this.#l=o,this.#d=r,this.#c=l,this.#u=d,this.#h=c,this.#g=u,this.#p=h,this.#f=g,e.on(this.#p.ownerDocument,this.#r.getBackSignal(),(()=>{this.#m()})),this.#p.querySelectorAll('[data-action="close"]').forEach((t=>{t.addEventListener("click",(()=>{this.#v()}))})),this.#r.addEngageListener((t=>{this.#w(t)})),this.#g.addEventListener("click",(()=>{this.#y()})),this.#t.forEach((t=>{this.#b(t)})),this.#c.querySelectorAll("li").forEach((t=>{const e=function(t){const e=t.getAttribute(b);if(null===e)throw new Error(`Could not find '${b}' attribbute of element.`);return e}(t);this.#T(t,e),this.selectNode(e)})),this.#w(this.#r.getCurrentLevel()),this.#S()}unselectNode(t){if(this.#x(t),this.#S(),this.#E(t),this.#t.has(t)){const e=this.#t.get(t);U(e.element,!1),this.#O(e.selectButton,e.name)}this.#f(this)}selectNode(t){if(this.#D(t),this.#S(),this.#t.has(t)){const e=this.#t.get(t);U(e.element,!0),this.#C(e.selectButton,e.name),this.#I(e)}this.#f(this)}engageNode(t){if(!this.#t.has(t))return;const e=this.#t.get(t).drilldownParentLevel;this.#r.getCurrentLevel()!==e&&this.#r.getParentLevel()!==e&&this.#r.engageLevel(e)}getSelection(){return new Set(this.#e)}getNodes(){return new Map(this.#t)}async#A(t){var e,n,i;if(!this.#n.has(t.id)&&!this.#i.has(t.id))try{this.#i.add(t.id);const s=await this.#a.loadContent(t.renderUrl);t.listElement.append(...s.children),this.#r.parseLevels();const a=q((i=t.listElement,Array.from(i.querySelectorAll(_))),this.#t),o=(e=a,n=this.#t,Array.from(e.entries()).filter((([t])=>!n.has(t))).map((([,t])=>t)));this.#t=a,R(o,(t=>{this.#e.has(t.id)?this.selectNode(t.id):this.unselectNode(t.id),this.#b(t)})),this.#n.add(t.id)}catch(t){throw new Error(`Could not render async node children: ${t.message}`)}finally{this.#i.delete(t.id)}}#M(t){R(function(t,e,n=255){const i=[];let s=t;for(let t=0;t{const e=t.getAttribute(b);if(null===e||!this.#t.has(e))throw new Error(`Could not find '${b}' of node element.`);const n=this.#t.get(e);this.#N(n)}))}#N(t){const e=this.#s.createContent(this.#d).querySelector(".crumb");e.setAttribute(x,t.drilldownParentLevel),e.firstElementChild.textContent=t.name,e.addEventListener("click",(()=>{this.#r.engageLevel(t.drilldownParentLevel),t.drilldownButton.click()})),this.#l.append(e)}#m(){const t=this.#l.querySelectorAll(".crumb");t.item(t.length-1)?.remove()}#_(){R(this.#l.querySelectorAll(".crumb"),(t=>{t.remove()}))}#w(t){if("0"===t)return void this.#_();const e=this.#p.querySelector(`ul[${x}="${t}"]`)?.closest(_)?.getAttribute(b);if(null===e||!this.#t.has(e))throw new Error(`Could not find node for drilldown-level '${t}'.`);const n=this.#t.get(e);this.#_(),this.#M(n),null!==n.renderUrl&&this.#A(n)}#T(t,e){t.querySelector(P)?.addEventListener("click",(()=>{this.unselectNode(e),t.remove()}))}#L(t,e){t.addEventListener("click",(()=>{this.#e.has(e.id)?this.unselectNode(e.id):this.selectNode(e.id)}))}#I(t){if(null!==this.#c.querySelector(`li[${b}="${t.id}"]`))return;const e=this.#s.createContent(this.#u),n=e.querySelector("[data-node-id]");n.setAttribute(b,t.id),n.querySelector(`[${T}]`).textContent=t.name,n.querySelector("input").value=t.id,this.#T(n,t.id),this.#c.append(...e.children)}#E(t){this.#c.querySelector(`li[${b}="${t}"]`)?.remove()}#b(t){this.#L(t.selectButton,t)}#O(t,e){t.querySelector(P)?.classList.add(A),t.querySelector(B)?.classList.remove(A),t.setAttribute("aria-label",this.#k("select_node",e))}#C(t,e){t.querySelector(B)?.classList.add(A),t.querySelector(P)?.classList.remove(A),t.setAttribute("aria-label",this.#k("unselect_node",e))}#S(){this.#h.disabled=this.#e.size<=0}#x(t){this.#e.has(t)&&this.#e.delete(t)}#D(t){this.#e.has(t)||this.#e.add(t)}#k(t,...e){return $(this.#o.txt(t),e)}#v(){this.#p.close()}#y(){this.#p.showModal()}}function z(t,e){const n=t.createDocumentFragment();return n.append(...e),n}function K(t,e,n){t.querySelectorAll(`[${n}]`).forEach((t=>{const i=t.getAttribute(n);if(!e.has(i))throw new Error(`Element references '${i}' which does not exist.`);t.setAttribute(n,e.get(i))}))}class X{#P;constructor(t){this.#P=t}createContent(t){const e=t.content.cloneNode(!0),n=new Map;return e.querySelectorAll("[id]").forEach((t=>{const e=function(t=""){return`${t}${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`}("il_ui_fw_");n.set(t.id,e),t.id=e})),e.querySelectorAll("[for]").forEach((t=>{t.htmlFor=n.get(t.htmlFor)})),K(e,n,"aria-describedby"),K(e,n,"aria-labelledby"),K(e,n,"aria-controls"),K(e,n,"aria-owns"),z(this.#P,e.children)}}class J{#P;constructor(t){this.#P=t}loadContent(t){return fetch(t.toString()).then((t=>t.text())).then((t=>this.#B(t))).then((t=>z(this.#P,t))).catch((e=>{throw new Error(`Could not render element(s) from '${t}': ${e.message}`)}))}#j(t){const e=this.#P.createElement("script");return t.hasAttribute("type")&&e.setAttribute("type",t.getAttribute("type")),t.hasAttribute("src")&&e.setAttribute("src",t.getAttribute("src")),t.textContent.length>0&&(e.textContent=t.textContent),e}#B(t){const e=this.#P.createElement("div");return e.innerHTML=t.trim(),e.querySelectorAll("script").forEach((t=>{const e=this.#j(t);t.replaceWith(e)})),e.children}}function Q(t){return Array.from(t.querySelectorAll(_))}function G(){return t=>{!function(t){const e=t.getNodes(),n=t.getSelection();e.forEach(((t,e)=>{n.size>0?(t.selectButton.disabled=!n.has(e),t.selectButton.querySelector(N).classList.toggle(M,!n.has(e))):(t.selectButton.disabled=!1,t.selectButton.querySelector(N).classList.toggle(M,!1))}))}(t),function(t){const e=t.getSelection();if(1===e.size){const n=e.values()?.next()?.value;t.getNodes().has(n)&&t.engageNode(n)}}(t)}}function Y(t){return t?()=>{}:t=>{!function(t){const e=Array.from(t.getSelection()),n=t.getNodes();for(let s=0;s{t.selectButton.disabled=!1,t.selectButton.querySelector(N).classList.remove(M)})),n.forEach((t=>{const n=e.get(t);null!==n&&null!==n.listElement&&n.listElement.querySelectorAll(j).forEach((t=>{t.disabled=!0,t.querySelector(N).classList.add(M)}))}))}(t)}}class Z{#V=new Map;#F;#H;#o;#P;constructor(t,e,n,i){this.#F=t,this.#H=e,this.#o=n,this.#P=i}initTreeMultiSelect(t,e){if(this.#V.has(t))throw new Error(`TreeSelect '${t}' already exists.`);const[n,i,s,a,o,r,l,d]=this.#q(t),c=this.#R(l),u=new W(q(Q(l)),this.#F,new X(this.#P),new J(this.#P),this.#o,c,s,a,o,r,d,n,l,Y(e));return this.#V.set(t,u),u}initTreeSelect(t){if(this.#V.has(t))throw new Error(`TreeSelect '${t}' already exists.`);const[e,n,i,s,a,o,r,l]=this.#q(t),d=this.#R(r),c=new W(q(Q(r)),this.#F,new X(this.#P),new J(this.#P),this.#o,d,i,s,a,o,l,e,r,G());return this.#V.set(t,c),c}getInstance(t){return this.#V.has(t)?this.#V.get(t):null}#q(t){const e=this.#P.getElementById(t),n=e?.closest(L),i=this.#P.getElementById(`${t}_dialog`)??n?.querySelector("dialog"),s=i?.querySelector(".breadcrumb"),a=i?.querySelector(".modal-body > template"),o=n?.querySelector(k),r=o?.querySelector(":scope > template"),l=i?.querySelector(".btn-primary");if(null===s||null===a||null===o||null===r||null===l||null===e||null===i)throw new Error(`Could not find some element(s) for Tree Select Input '${t}'.`);return[e,n,s,a,o,r,i,l]}#R(t){const e=t.querySelector(".c-drilldown");if(null===e||!e.hasAttribute("id"))throw new Error("Could not find drilldown element.");const n=this.#H.getInstance(e.id);if(null===e)throw new Error("Could not find drilldown instance.");return n}}class tt{#$;constructor(t){this.#$=t}on(t,e,n){this.#$(t).on(e,n)}off(t,e,n){this.#$(t).off(e,n)}} /* Tagify v4.33.2 - tags input component By: Yair Even-Or diff --git a/components/ILIAS/UI/resources/js/Input/Field/src/TreeSelect/TreeSelectFactory.js b/components/ILIAS/UI/resources/js/Input/Field/src/TreeSelect/TreeSelectFactory.js index 8f7bc555bda3..e86251771c24 100644 --- a/components/ILIAS/UI/resources/js/Input/Field/src/TreeSelect/TreeSelectFactory.js +++ b/components/ILIAS/UI/resources/js/Input/Field/src/TreeSelect/TreeSelectFactory.js @@ -113,7 +113,7 @@ export default class TreeSelectFactory { dialogSelectButton, ] = this.#getTreeSelectElements(inputId); - const drilldownComponent = this.#getDrilldown(treeSelectElement); + const drilldownComponent = this.#getDrilldown(dialogElement); const treeMultiSelect = new TreeSelect( createTreeSelectNodes(getNodeElements(dialogElement)), @@ -157,7 +157,7 @@ export default class TreeSelectFactory { dialogSelectButton, ] = this.#getTreeSelectElements(inputId); - const drilldownComponent = this.#getDrilldown(treeSelectElement); + const drilldownComponent = this.#getDrilldown(dialogElement); const treeSelect = new TreeSelect( createTreeSelectNodes(getNodeElements(dialogElement)), @@ -200,11 +200,12 @@ export default class TreeSelectFactory { #getTreeSelectElements(inputId) { const dialogOpenButton = this.#document.getElementById(inputId); const treeSelectElement = dialogOpenButton?.closest(CONSTANTS.TREE_SELECT); - const breadcrumbsElement = treeSelectElement?.querySelector(CONSTANTS.BREADCRUMB); - const breadcrumbTemplate = treeSelectElement?.querySelector('.modal-body > template'); + const dialogElement = this.#document.getElementById(`${inputId}_dialog`) + ?? treeSelectElement?.querySelector('dialog'); + const breadcrumbsElement = dialogElement?.querySelector(CONSTANTS.BREADCRUMB); + const breadcrumbTemplate = dialogElement?.querySelector('.modal-body > template'); const nodeSelectionElement = treeSelectElement?.querySelector(CONSTANTS.TREE_SELECT_SELECTION); const nodeSelectionTemplate = nodeSelectionElement?.querySelector(':scope > template'); - const dialogElement = treeSelectElement?.querySelector('dialog'); const dialogSelectButton = dialogElement?.querySelector(CONSTANTS.TREE_SELECT_BUTTON); if (breadcrumbsElement === null @@ -231,12 +232,12 @@ export default class TreeSelectFactory { } /** - * @param {HTMLDivElement} element + * @param {HTMLElement} container dialog or legacy wrapper containing the drilldown * @returns {Drilldown} * @throws {Error} if instance can not be found */ - #getDrilldown(element) { - const drilldownElement = element.querySelector(CONSTANTS.DRILLDOWN); + #getDrilldown(container) { + const drilldownElement = container.querySelector(CONSTANTS.DRILLDOWN); if (drilldownElement === null || !drilldownElement.hasAttribute('id')) { throw new Error('Could not find drilldown element.'); } diff --git a/components/ILIAS/UI/resources/js/Modal/dist/modal.min.js b/components/ILIAS/UI/resources/js/Modal/dist/modal.min.js index f82345963d2f..c73b6793ce9e 100644 --- a/components/ILIAS/UI/resources/js/Modal/dist/modal.min.js +++ b/components/ILIAS/UI/resources/js/Modal/dist/modal.min.js @@ -12,4 +12,4 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(e,t){"use strict";const i={maybeInitCarousel(e){const t=e.querySelector(".carousel-inner");if(!t||t.querySelectorAll(".item").length<2)return;const i=e.querySelector(".carousel-control.left"),r=e.querySelector(".carousel-control.right"),o=e.querySelectorAll(".carousel-indicators > li");i.addEventListener("click",(()=>this.nextPage(e,-1))),r.addEventListener("click",(()=>this.nextPage(e,1))),o.forEach((t=>t.addEventListener("click",(()=>this.gotoPage(e,Number(t.getAttribute("data-slide-to")))))))},nextPage(e,t){const i=e.querySelectorAll(".carousel-inner > .item");let r=0,o=0;i.forEach((e=>{e.classList.contains("active")&&(o=r),r+=1}));let l=o+t;l<0&&(l=r-1),l===r&&(l=0),this.gotoPage(e,l)},gotoPage(e,t){const i=e.querySelectorAll(".carousel-inner > .item"),r=e.querySelectorAll(".carousel-indicators > li");this.setActiveInList(i,t),this.setActiveInList(r,t);const o=e.querySelector(".modal-title");i.forEach((e=>{e.classList.contains("active")&&(o.innerHTML=e.getAttribute("data-title"))}))},setActiveInList(e,t){let i=0;e.forEach((e=>{i!==t?e.classList.remove("active"):e.classList.add("active"),i+=1}))}};e.UI=e.UI||{},e.UI.modal=new class{#e;#t=[];#i={};constructor(e){this.#e=e}showModal(e,t,i,r){if(!e||"DIALOG"!==e?.tagName&&!t?.ajaxRenderUrl)throw new Error("component is not a dialog (or triggers one).");r&&this.#e(e.ownerDocument).on(r,(()=>e.close())),!0!==this.#t[i.id]&&(this.#t[i.id]=!0,t.ajaxRenderUrl?this.#e(e).load(t.ajaxRenderUrl,(()=>{const t=e.querySelector("dialog");if(!t)throw new Error("url did not return a dialog");t.showModal(),il.UI.lightbox.maybeInitCarousel(e),this.#t[i.id]=!1})):(e.showModal(),il.UI.lightbox.maybeInitCarousel(e),this.#t[i.id]=!1),this.#i[i.id]=e.id)}}(t),e.UI.lightbox=i}(il,$); +!function(e,t){"use strict";const o={maybeInitCarousel(e){const t=e.querySelector(".carousel-inner");if(!t||t.querySelectorAll(".item").length<2)return;const o=e.querySelector(".carousel-control.left"),i=e.querySelector(".carousel-control.right"),r=e.querySelectorAll(".carousel-indicators > li");o.addEventListener("click",(()=>this.nextPage(e,-1))),i.addEventListener("click",(()=>this.nextPage(e,1))),r.forEach((t=>t.addEventListener("click",(()=>this.gotoPage(e,Number(t.getAttribute("data-slide-to")))))))},nextPage(e,t){const o=e.querySelectorAll(".carousel-inner > .item");let i=0,r=0;o.forEach((e=>{e.classList.contains("active")&&(r=i),i+=1}));let a=r+t;a<0&&(a=i-1),a===i&&(a=0),this.gotoPage(e,a)},gotoPage(e,t){const o=e.querySelectorAll(".carousel-inner > .item"),i=e.querySelectorAll(".carousel-indicators > li");this.setActiveInList(o,t),this.setActiveInList(i,t);const r=e.querySelector(".modal-title");o.forEach((e=>{e.classList.contains("active")&&(r.innerHTML=e.getAttribute("data-title"))}))},setActiveInList(e,t){let o=0;e.forEach((e=>{o!==t?e.classList.remove("active"):e.classList.add("active"),o+=1}))}};e.UI=e.UI||{},e.UI.modal=new class{#e;#t=[];#o={};constructor(e){this.#e=e,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",(()=>this.#i())):this.#i()}#i(){document.querySelectorAll("dialog").forEach((e=>{if(e.parentElement?.closest("dialog"))return;const t=e.ownerDocument.body;t&&e.parentElement!==t&&t.appendChild(e)}))}#r(e){if(!e||"DIALOG"!==e.tagName)return;const t=e.ownerDocument.body;t&&e.parentElement!==t&&t.appendChild(e)}showModal(e,t,o,i){if(!e||"DIALOG"!==e?.tagName&&!t?.ajaxRenderUrl)throw new Error("component is not a dialog (or triggers one).");i&&this.#e(e.ownerDocument).on(i,(()=>e.close())),!0!==this.#t[o.id]&&(this.#t[o.id]=!0,"DIALOG"===e.tagName&&this.#r(e),t.ajaxRenderUrl?this.#e(e).load(t.ajaxRenderUrl,(()=>{const t=e.querySelector("dialog");if(!t)throw new Error("url did not return a dialog");this.#r(t),t.showModal(),il.UI.lightbox.maybeInitCarousel(e),this.#t[o.id]=!1})):(e.showModal(),il.UI.lightbox.maybeInitCarousel(e),this.#t[o.id]=!1),this.#o[o.id]=e.id)}}(t),e.UI.lightbox=o}(il,$); diff --git a/components/ILIAS/UI/resources/js/Modal/rollup.config.js b/components/ILIAS/UI/resources/js/Modal/rollup.config.js index 6f86a14bc658..feb38fa0cfa5 100644 --- a/components/ILIAS/UI/resources/js/Modal/rollup.config.js +++ b/components/ILIAS/UI/resources/js/Modal/rollup.config.js @@ -15,8 +15,8 @@ ******************************************************************** */ import terser from '@rollup/plugin-terser'; -import copyright from '../../../../../../scripts/Copyright-Checker/copyright'; -import preserveCopyright from '../../../../../../scripts/Copyright-Checker/preserveCopyright'; +import copyright from '../../../../../../scripts/Copyright-Checker/copyright.js'; +import preserveCopyright from '../../../../../../scripts/Copyright-Checker/preserveCopyright.js'; export default { input: './src/index.js', diff --git a/components/ILIAS/UI/resources/js/Modal/src/Modal.js b/components/ILIAS/UI/resources/js/Modal/src/Modal.js index e9f36ba59d82..48bfa016e342 100644 --- a/components/ILIAS/UI/resources/js/Modal/src/Modal.js +++ b/components/ILIAS/UI/resources/js/Modal/src/Modal.js @@ -34,6 +34,41 @@ export default class Modal { */ constructor(jquery) { this.#jquery = jquery; + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => this.#moveModalsToBody()); + } else { + this.#moveModalsToBody(); + } + } + + /** + * Reparents every native to document.body so headings inside dialogs + * do not sit between main-content headings in document order. Call sites that + * previously used descendant selectors must resolve dialogs by id instead. + */ + #moveModalsToBody() { + document.querySelectorAll('dialog').forEach((dialog) => { + if (dialog.parentElement?.closest('dialog')) { + return; + } + const body = dialog.ownerDocument.body; + if (body && dialog.parentElement !== body) { + body.appendChild(dialog); + } + }); + } + + /** + * @param {HTMLDialogElement|null|undefined} dialog + */ + #ensureDialogInBody(dialog) { + if (!dialog || dialog.tagName !== 'DIALOG') { + return; + } + const body = dialog.ownerDocument.body; + if (body && dialog.parentElement !== body) { + body.appendChild(dialog); + } } /** @@ -61,12 +96,17 @@ export default class Modal { } this.#triggeredSignalsStorage[signalData.id] = true; + if (component.tagName === 'DIALOG') { + this.#ensureDialogInBody(component); + } + if (options.ajaxRenderUrl) { this.#jquery(component).load(options.ajaxRenderUrl, () => { const dialog = component.querySelector('dialog'); if (!dialog) { throw new Error('url did not return a dialog'); } + this.#ensureDialogInBody(dialog); dialog.showModal(); il.UI.lightbox.maybeInitCarousel(component); this.#triggeredSignalsStorage[signalData.id] = false; diff --git a/components/ILIAS/UI/resources/js/Prompt/dist/prompt.min.js b/components/ILIAS/UI/resources/js/Prompt/dist/prompt.min.js index 788838ffbdba..94480b2aca69 100644 --- a/components/ILIAS/UI/resources/js/Prompt/dist/prompt.min.js +++ b/components/ILIAS/UI/resources/js/Prompt/dist/prompt.min.js @@ -12,4 +12,4 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(t,e){"use strict";class r{#t;#e;#r;constructor(t,e){if(this.#t=t,this.#e=document.getElementById(e),null===this.#e)throw new Error(`Could not find a Prompt for id '${e}'.`);this.#r=this.#e.getElementsByTagName("dialog").item(0)}show(t){this.load(t),this.#r.showModal()}close(){this.#r.close()}async load(t,e={}){await fetch(t,e).then((t=>t.text())).then((t=>{const e=(new this.#t).parseFromString(t,"text/html"),r=e.querySelector('section[data-section="il-prompt-state__title"]'),n=e.querySelector('section[data-section="il-prompt-state__contents"]'),o=e.querySelector('section[data-section="il-prompt-state__buttons"]'),i=e.querySelector('section[data-section="il-prompt-state__command"]'),s=e.querySelector('section[data-section="il-prompt-state__parameters"]'),a=e.querySelector("script"),c=this.#r.querySelector("span.il-prompt__title"),p=this.#r.querySelector("div.il-prompt__contents"),l=this.#r.querySelector("div.il-prompt__buttons");c.innerHTML=r.innerHTML,p.innerHTML=n.innerHTML,l.innerHTML=o.innerHTML,this.#n(p),this.#o(p),a&&this.#i(a.text);const m=[];return s.querySelectorAll("data").forEach((t=>{m[t.innerHTML.trim()]=t.getAttribute("value")})),{cmd:i.innerHTML.trim(),params:m}})).then((t=>{const e=t.cmd,{params:r}=t;"close"===e&&this.close(),"redirect"===e&&window.location.replace(r.redirect)}))}#i(t){const e=this.#e.querySelector("section.il-prompt__scripts"),r=document.createElement("script");r.text=t,e.innerHTML="",e.appendChild(r)}#n(t){t.getElementsByTagName("form").forEach((t=>{t.addEventListener("submit",(e=>{e.preventDefault(),this.load(t.action,{method:t.method,body:new FormData(t)})}))}))}#o(t){t.getElementsByTagName("a").forEach((t=>{const{target:e}=t;if("_blank"!==e){const e=t.href;t.addEventListener("click",(()=>this.load(e))),t.removeAttribute("href")}}))}}t.UI=t.UI||{},t.UI.prompt=new class{#t;#s=[];constructor(t){this.#t=t}init(t){if(void 0!==this.#s[t])throw new Error(`Prompt with id '${t}' has already been initialized.`);this.#s[t]=new r(this.#t,t)}get(t){return this.#s[t]??null}}(e)}(il,DOMParser); +!function(t,e){"use strict";class r{#t;#e;#r;constructor(t,e){if(this.#t=t,this.#e=document.getElementById(e),null===this.#e)throw new Error(`Could not find a Prompt for id '${e}'.`);if(this.#r=document.getElementById(`${e}_dialog`),null===this.#r)throw new Error(`Could not find dialog for Prompt '${e}'.`)}show(t){this.load(t),this.#r.showModal()}close(){this.#r.close()}async load(t,e={}){await fetch(t,e).then((t=>t.text())).then((t=>{const e=(new this.#t).parseFromString(t,"text/html"),r=e.querySelector('section[data-section="il-prompt-state__title"]'),o=e.querySelector('section[data-section="il-prompt-state__contents"]'),n=e.querySelector('section[data-section="il-prompt-state__buttons"]'),i=e.querySelector('section[data-section="il-prompt-state__command"]'),s=e.querySelector('section[data-section="il-prompt-state__parameters"]'),a=e.querySelector("script"),c=this.#r.querySelector("span.il-prompt__title"),p=this.#r.querySelector("div.il-prompt__contents"),l=this.#r.querySelector("div.il-prompt__buttons");c.innerHTML=r.innerHTML,p.innerHTML=o.innerHTML,l.innerHTML=n.innerHTML,this.#o(p),this.#n(p),a&&this.#i(a.text);const m=[];return s.querySelectorAll("data").forEach((t=>{m[t.innerHTML.trim()]=t.getAttribute("value")})),{cmd:i.innerHTML.trim(),params:m}})).then((t=>{const e=t.cmd,{params:r}=t;"close"===e&&this.close(),"redirect"===e&&window.location.replace(r.redirect)}))}#i(t){const e=this.#e.querySelector("section.il-prompt__scripts"),r=document.createElement("script");r.text=t,e.innerHTML="",e.appendChild(r)}#o(t){t.getElementsByTagName("form").forEach((t=>{t.addEventListener("submit",(e=>{e.preventDefault(),this.load(t.action,{method:t.method,body:new FormData(t)})}))}))}#n(t){t.getElementsByTagName("a").forEach((t=>{const{target:e}=t;if("_blank"!==e){const e=t.href;t.addEventListener("click",(()=>this.load(e))),t.removeAttribute("href")}}))}}t.UI=t.UI||{},t.UI.prompt=new class{#t;#s=[];constructor(t){this.#t=t}init(t){if(void 0!==this.#s[t])throw new Error(`Prompt with id '${t}' has already been initialized.`);this.#s[t]=new r(this.#t,t)}get(t){return this.#s[t]??null}}(e)}(il,DOMParser); diff --git a/components/ILIAS/UI/resources/js/Prompt/rollup.config.js b/components/ILIAS/UI/resources/js/Prompt/rollup.config.js index f815677b5a1a..b2bbcc13ce48 100644 --- a/components/ILIAS/UI/resources/js/Prompt/rollup.config.js +++ b/components/ILIAS/UI/resources/js/Prompt/rollup.config.js @@ -15,8 +15,8 @@ ******************************************************************** */ import terser from '@rollup/plugin-terser'; -import copyright from '../../../../../../scripts/Copyright-Checker/copyright'; -import preserveCopyright from '../../../../../../scripts/Copyright-Checker/preserveCopyright'; +import copyright from '../../../../../../scripts/Copyright-Checker/copyright.js'; +import preserveCopyright from '../../../../../../scripts/Copyright-Checker/preserveCopyright.js'; export default { input: './src/prompt.js', diff --git a/components/ILIAS/UI/resources/js/Prompt/src/prompt.class.js b/components/ILIAS/UI/resources/js/Prompt/src/prompt.class.js index e34ae4065d9a..d009e61b32d0 100644 --- a/components/ILIAS/UI/resources/js/Prompt/src/prompt.class.js +++ b/components/ILIAS/UI/resources/js/Prompt/src/prompt.class.js @@ -25,7 +25,7 @@ export default class Prompt { #component; /** - * @type {HTMLPromptElement} + * @type {HTMLDialogElement} */ #prompt; @@ -40,7 +40,10 @@ export default class Prompt { if (this.#component === null) { throw new Error(`Could not find a Prompt for id '${componentId}'.`); } - this.#prompt = this.#component.getElementsByTagName('dialog').item(0); + this.#prompt = document.getElementById(`${componentId}_dialog`); + if (this.#prompt === null) { + throw new Error(`Could not find dialog for Prompt '${componentId}'.`); + } } /** diff --git a/components/ILIAS/UI/resources/js/Table/dist/table.min.js b/components/ILIAS/UI/resources/js/Table/dist/table.min.js index 823b92627136..bcf09b5974ca 100644 --- a/components/ILIAS/UI/resources/js/Table/dist/table.min.js +++ b/components/ILIAS/UI/resources/js/Table/dist/table.min.js @@ -12,4 +12,4 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(e,t){"use strict";class s{#e;#t;#s;#i;#a;#o;#n;#r;constructor(e,t,s,i){if(this.#s=document.getElementById(i),null===this.#s)throw new Error(`Could not find a DataTable for id '${i}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no in the component's HTML.");this.#i=this.#s.getElementsByClassName("c-table-data__async_modal_container").item(0),this.#a=this.#s.getElementsByClassName("c-table-data__async_message").item(0),this.#o=this.#a.getElementsByClassName("c-table-data__async_messageresponse").item(0),this.#e=e,this.#t={actionId:t,rowId:s},this.#r={},this.#s.addEventListener("keydown",(e=>this.navigateCellsWithArrowKeys(e)));const a=this.#n.getElementsByClassName("c-table-data__row-selector");for(let e=0;ethis.selectionChange()))}}registerAction(e,t,s,i){this.#r[e]={async:t,urlBuilder:s,urlTokens:i}}selectionChange(){this.#l(!this.#c())}#c(){const{urlBuilder:e}=this.#r[Object.keys(this.#r).at(0)],{urlTokens:t}=this.#r[Object.keys(this.#r).at(0)],s=t.values().next().value,i=this.collectSelectedRowIds();i.push(i[0]),e.writeParameter(s,i);try{e.getUrl().toString()}catch(e){return!1}return!0}#h(){const e=this.#s.querySelector("dialog.c-table-data__multiaction-warning");il.UI.modal.showModal(e,{},{id:e.id})}#l(e){this.#n.getElementsByClassName("c-table-data__row-selector").forEach((t=>{t.disabled=!0===e&&!t.checked}))}selectAll(e){const t=this.#n.getElementsByClassName("c-table-data__row-selector"),s=this.#n.getElementsByClassName("c-table-data__selection_all").item(0),i=this.#n.getElementsByClassName("c-table-data__selection_none").item(0);for(let s=0;s{e.checked&&t.push(e.value)})),t}doMultiAction(e){this.doAction(e,this.collectSelectedRowIds())}doSingleAction(e){const t=e.options[this.#t.rowId];this.doAction(e,[t])}doActionForAll(e){const t=e.parentNode.parentNode.parentNode,s=t.getElementsByClassName("close").item(0),i=t.getElementsByClassName("modal-body")[0].getElementsByTagName("select")[0].value;if(i in this.#r){const e=this.#t.actionId,t={options:{}};t.options[e]=i,s.click(),this.doAction(t,["ALL_OBJECTS"])}}doAction(e,t){const s=e.options[this.#t.actionId],i=this.#r[s],a=i.urlTokens.values().next().value;i.urlBuilder.writeParameter(a,t);const o=decodeURI(i.urlBuilder.getUrl().toString());i.async?this.asyncAction(o):window.location.href=o}asyncAction(e){this.#e.ajax({url:e,dataType:"html"}).done((e=>{if("SCRIPT"===this.#e(e).first().prop("tagName"))this.#e.globalEval(this.#e(e).first().text());else{let t;this.#e(e).first().hasClass("c-modal")?(this.#i.innerHTML=e,t=this.#i.firstChild):(this.#o.innerHTML=e,t=this.#a);this.#e(`
${e}
`).find("[data-replace-marker='script']").each(((e,t)=>this.#e.globalEval(t.innerHTML))),il.UI.modal.showModal(t,{},{id:t.id})}}))}navigateCellsWithArrowKeys(e){if(37!==e.which&&38!==e.which&&39!==e.which&&40!==e.which)return;const t=e.target.closest("td, th"),s=t.closest("tr");let{cellIndex:i}=t,{rowIndex:a}=s;switch(e.which){case 37:i-=1;break;case 39:i+=1;break;case 38:a-=1;break;case 40:a+=1}a<0||i<0||a>=this.#n.rows.length||i>=s.cells.length||this.focusCell(t,a,i)}focusCell(e,t,s){const i=this.#n.rows[t].cells[s];i.focus(),e.setAttribute("tabindex",-1),i.setAttribute("tabindex",0)}}class i{#s;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a PresentationTable for id '${e}'.`)}expandRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("collapsed"),t.classList.add("expanded")}collapseRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("expanded"),t.classList.add("collapsed")}toggleRow(e){this.#s.querySelector(`#${e}`).classList.contains("expanded")?this.collapseRow(e):this.expandRow(e)}expandAll(e){const t=this.#s.querySelectorAll(".il-table-presentation-row");e.options.expand?t.forEach((e=>this.expandRow(e.id))):t.forEach((e=>this.collapseRow(e.id)))}}class a{#s;#n;#d;#g;#w;#m;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a OrderingTable for id '${e}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no
in the component's HTML.");this.#p(),this.#d.forEach((e=>this.#u(e)))}#p(){this.#d=Array.from(this.#n.rows),this.#d.shift(),this.#d.pop()}#u(e){e.addEventListener("dragstart",(e=>this.dragstart(e))),e.addEventListener("dragover",(e=>this.dragover(e))),e.addEventListener("dragend",(e=>this.dragend(e))),e.addEventListener("touchstart",(e=>this.touchstart(e))),e.addEventListener("touchmove",(e=>this.touchmove(e))),e.addEventListener("touchend",(e=>this.touchend(e))),e.addEventListener("touchcancel",(e=>this.touchend(e)))}dragstart(e){this.#s.classList.add("dragInProgress"),this.#g=e.target.closest("tr"),e.dataTransfer.clearData(),e.dataTransfer.setData("text/html",this.#g.outerHTML),e.dataTransfer.setData("text/plain",this.#g.textContent.replace(/[\n\r]+|[\s]{2,}/g," ").trim()),this.#w=this.#g.cloneNode(!0),this.#w.classList.add("c-table-data__row--drag-image"),this.#w.style.top="-9999px",this.#s.appendChild(this.#w),e.dataTransfer.setDragImage(this.#w,0,0),this.#m=this.#g.cloneNode(!0),this.#m.addEventListener("dragover",(e=>this.dragover(e))),this.#m.classList.add("c-table-data__row--placeholder"),Array.from(this.#m.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#g.classList.add("c-table-data__row--drag-origin")}dragover(e){if(!this.#b())return;e.preventDefault(),e.dataTransfer.effectAllowed="copyMove";const t=e.target.closest("tr");t&&t!==this.#m&&(this.#d.indexOf(t)>this.#d.indexOf(this.#g)?t.after(this.#m):t.before(this.#m))}dragend(e){e.preventDefault(),this.#w&&this.#s.contains(this.#w)&&(this.#s.removeChild(this.#w),this.#w=null),this.#m.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#g.classList.add("c-table-data__row--drag-settle"),this.#g.addEventListener("animationend",(()=>this.#y()),{once:!0}),this.#s.classList.remove("dragInProgress"),this.#p(),this.#R()}#y(){this.#g.classList.remove("c-table-data__row--drag-settle")}#b(){return this.#d.includes(this.#g)}touchstart(e){this.#g=e.target.closest("tr"),this.#m=this.#g.cloneNode(!0),this.#m.classList.add("c-table-data__row--placeholder"),Array.from(this.#m.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#w=this.#g.cloneNode(!0),this.#w.classList.add("c-table-data__row--touch-drag-image"),this.#s.appendChild(this.#w),this.#g.classList.add("c-table-data__row--drag-origin")}touchmove(e){e.preventDefault();const t=e.touches[0];this.#w.style.left=`${t.clientX+-50}px`,this.#w.style.top=`${t.clientY}px`;const s=document.elementFromPoint(t.clientX,t.clientY)?.closest("tr");s&&this.#d.includes(s)&&(this.#d.indexOf(s)>this.#d.indexOf(this.#g)?s.after(this.#m):s.before(this.#m)),t.clientY<100?this.#f(-8):t.clientY>window.innerHeight-100?this.#f(8):this.#v()}touchend(){this.#s.removeChild(this.#w),this.#m.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#p(),this.#R()}#R(){let e=10;this.#n.querySelectorAll('input[type="number"]').forEach((t=>{t.value=e,e+=10}))}#f(e){this.scrollInterval||(this.scrollInterval=setInterval((()=>{window.scrollBy(0,e)}),16))}#v(){this.scrollInterval&&(clearInterval(this.scrollInterval),this.scrollInterval=null)}}e.UI=e.UI||{},e.UI.table=e.UI.table||{},e.UI.table.data=new class{#e;#E=[];constructor(e){this.#e=e}init(e,t,i){if(void 0!==this.#E[e])throw new Error(`DataTable with id '${e}' has already been initialized.`);this.#E[e]=new s(this.#e,t,i,e)}get(e){return this.#E[e]??null}}(t),e.UI.table.presentation=new class{#E=[];init(e){if(void 0!==this.#E[e])throw new Error(`PresentationTable with input-id '${e}' has already been initialized.`);this.#E[e]=new i(e)}get(e){return this.#E[e]??null}},e.UI.table.ordering=new class{#E=[];init(e){if(void 0!==this.#E[e])throw new Error(`OrderingTable with id '${e}' has already been initialized.`);this.#E[e]=new a(e)}get(e){return this.#E[e]??null}}}(il,$); +!function(e,t){"use strict";class s{#e;#t;#s;#i;#o;#a;#n;#r;constructor(e,t,s,i){if(this.#s=document.getElementById(i),null===this.#s)throw new Error(`Could not find a DataTable for id '${i}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no
in the component's HTML.");if(this.#i=this.#s.getElementsByClassName("c-table-data__async_modal_container").item(0),this.#o=document.getElementById(`${i}_msgmodal`)??this.#s.getElementsByClassName("c-table-data__async_message").item(0),null===this.#o)throw new Error("Could not find async message container for this table.");this.#a=this.#o.getElementsByClassName("c-table-data__async_messageresponse").item(0),this.#e=e,this.#t={actionId:t,rowId:s},this.#r={},this.#s.addEventListener("keydown",(e=>this.navigateCellsWithArrowKeys(e)));const o=this.#n.getElementsByClassName("c-table-data__row-selector");for(let e=0;ethis.selectionChange()))}}registerAction(e,t,s,i){this.#r[e]={async:t,urlBuilder:s,urlTokens:i}}selectionChange(){this.#l(!this.#c())}#c(){const{urlBuilder:e}=this.#r[Object.keys(this.#r).at(0)],{urlTokens:t}=this.#r[Object.keys(this.#r).at(0)],s=t.values().next().value,i=this.collectSelectedRowIds();i.push(i[0]),e.writeParameter(s,i);try{e.getUrl().toString()}catch(e){return!1}return!0}#d(){const e=document.getElementById(`${this.#s.id}_warningmodal`);null!==e&&il.UI.modal.showModal(e,{},{id:e.id})}#l(e){this.#n.getElementsByClassName("c-table-data__row-selector").forEach((t=>{t.disabled=!0===e&&!t.checked}))}selectAll(e){const t=this.#n.getElementsByClassName("c-table-data__row-selector"),s=this.#n.getElementsByClassName("c-table-data__selection_all").item(0),i=this.#n.getElementsByClassName("c-table-data__selection_none").item(0);for(let s=0;s{e.checked&&t.push(e.value)})),t}doMultiAction(e){this.doAction(e,this.collectSelectedRowIds())}doSingleAction(e){const t=e.options[this.#t.rowId];this.doAction(e,[t])}doActionForAll(e){const t=e.parentNode.parentNode.parentNode,s=t.getElementsByClassName("close").item(0),i=t.getElementsByClassName("modal-body")[0].getElementsByTagName("select")[0].value;if(i in this.#r){const e=this.#t.actionId,t={options:{}};t.options[e]=i,s.click(),this.doAction(t,["ALL_OBJECTS"])}}doAction(e,t){const s=e.options[this.#t.actionId],i=this.#r[s],o=i.urlTokens.values().next().value;i.urlBuilder.writeParameter(o,t);const a=decodeURI(i.urlBuilder.getUrl().toString());i.async?this.asyncAction(a):window.location.href=a}asyncAction(e){this.#e.ajax({url:e,dataType:"html"}).done((e=>{if("SCRIPT"===this.#e(e).first().prop("tagName"))this.#e.globalEval(this.#e(e).first().text());else{let t;this.#e(e).first().hasClass("c-modal")?(this.#i.innerHTML=e,t=this.#i.firstChild):(this.#a.innerHTML=e,t=this.#o);this.#e(`
${e}
`).find("[data-replace-marker='script']").each(((e,t)=>this.#e.globalEval(t.innerHTML))),il.UI.modal.showModal(t,{},{id:t.id})}}))}navigateCellsWithArrowKeys(e){if(37!==e.which&&38!==e.which&&39!==e.which&&40!==e.which)return;const t=e.target.closest("td, th"),s=t.closest("tr");let{cellIndex:i}=t,{rowIndex:o}=s;switch(e.which){case 37:i-=1;break;case 39:i+=1;break;case 38:o-=1;break;case 40:o+=1}o<0||i<0||o>=this.#n.rows.length||i>=s.cells.length||this.focusCell(t,o,i)}focusCell(e,t,s){const i=this.#n.rows[t].cells[s];i.focus(),e.setAttribute("tabindex",-1),i.setAttribute("tabindex",0)}}class i{#s;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a PresentationTable for id '${e}'.`)}expandRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("collapsed"),t.classList.add("expanded")}collapseRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("expanded"),t.classList.add("collapsed")}toggleRow(e){this.#s.querySelector(`#${e}`).classList.contains("expanded")?this.collapseRow(e):this.expandRow(e)}expandAll(e){const t=this.#s.querySelectorAll(".il-table-presentation-row");e.options.expand?t.forEach((e=>this.expandRow(e.id))):t.forEach((e=>this.collapseRow(e.id)))}}class o{#s;#n;#h;#g;#m;#w;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a OrderingTable for id '${e}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no
in the component's HTML.");this.#p(),this.#h.forEach((e=>this.#u(e)))}#p(){this.#h=Array.from(this.#n.rows),this.#h.shift(),this.#h.pop()}#u(e){e.addEventListener("dragstart",(e=>this.dragstart(e))),e.addEventListener("dragover",(e=>this.dragover(e))),e.addEventListener("dragend",(e=>this.dragend(e))),e.addEventListener("touchstart",(e=>this.touchstart(e))),e.addEventListener("touchmove",(e=>this.touchmove(e))),e.addEventListener("touchend",(e=>this.touchend(e))),e.addEventListener("touchcancel",(e=>this.touchend(e)))}dragstart(e){this.#s.classList.add("dragInProgress"),this.#g=e.target.closest("tr"),e.dataTransfer.clearData(),e.dataTransfer.setData("text/html",this.#g.outerHTML),e.dataTransfer.setData("text/plain",this.#g.textContent.replace(/[\n\r]+|[\s]{2,}/g," ").trim()),this.#m=this.#g.cloneNode(!0),this.#m.classList.add("c-table-data__row--drag-image"),this.#m.style.top="-9999px",this.#s.appendChild(this.#m),e.dataTransfer.setDragImage(this.#m,0,0),this.#w=this.#g.cloneNode(!0),this.#w.addEventListener("dragover",(e=>this.dragover(e))),this.#w.classList.add("c-table-data__row--placeholder"),Array.from(this.#w.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#g.classList.add("c-table-data__row--drag-origin")}dragover(e){if(!this.#y())return;e.preventDefault(),e.dataTransfer.effectAllowed="copyMove";const t=e.target.closest("tr");t&&t!==this.#w&&(this.#h.indexOf(t)>this.#h.indexOf(this.#g)?t.after(this.#w):t.before(this.#w))}dragend(e){e.preventDefault(),this.#m&&this.#s.contains(this.#m)&&(this.#s.removeChild(this.#m),this.#m=null),this.#w.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#g.classList.add("c-table-data__row--drag-settle"),this.#g.addEventListener("animationend",(()=>this.#b()),{once:!0}),this.#s.classList.remove("dragInProgress"),this.#p(),this.#R()}#b(){this.#g.classList.remove("c-table-data__row--drag-settle")}#y(){return this.#h.includes(this.#g)}touchstart(e){this.#g=e.target.closest("tr"),this.#w=this.#g.cloneNode(!0),this.#w.classList.add("c-table-data__row--placeholder"),Array.from(this.#w.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#m=this.#g.cloneNode(!0),this.#m.classList.add("c-table-data__row--touch-drag-image"),this.#s.appendChild(this.#m),this.#g.classList.add("c-table-data__row--drag-origin")}touchmove(e){e.preventDefault();const t=e.touches[0];this.#m.style.left=`${t.clientX+-50}px`,this.#m.style.top=`${t.clientY}px`;const s=document.elementFromPoint(t.clientX,t.clientY)?.closest("tr");s&&this.#h.includes(s)&&(this.#h.indexOf(s)>this.#h.indexOf(this.#g)?s.after(this.#w):s.before(this.#w)),t.clientY<100?this.#f(-8):t.clientY>window.innerHeight-100?this.#f(8):this.#v()}touchend(){this.#s.removeChild(this.#m),this.#w.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#p(),this.#R()}#R(){let e=10;this.#n.querySelectorAll('input[type="number"]').forEach((t=>{t.value=e,e+=10}))}#f(e){this.scrollInterval||(this.scrollInterval=setInterval((()=>{window.scrollBy(0,e)}),16))}#v(){this.scrollInterval&&(clearInterval(this.scrollInterval),this.scrollInterval=null)}}e.UI=e.UI||{},e.UI.table=e.UI.table||{},e.UI.table.data=new class{#e;#E=[];constructor(e){this.#e=e}init(e,t,i){if(void 0!==this.#E[e])throw new Error(`DataTable with id '${e}' has already been initialized.`);this.#E[e]=new s(this.#e,t,i,e)}get(e){return this.#E[e]??null}}(t),e.UI.table.presentation=new class{#E=[];init(e){if(void 0!==this.#E[e])throw new Error(`PresentationTable with input-id '${e}' has already been initialized.`);this.#E[e]=new i(e)}get(e){return this.#E[e]??null}},e.UI.table.ordering=new class{#E=[];init(e){if(void 0!==this.#E[e])throw new Error(`OrderingTable with id '${e}' has already been initialized.`);this.#E[e]=new o(e)}get(e){return this.#E[e]??null}}}(il,$); diff --git a/components/ILIAS/UI/resources/js/Table/src/datatable.class.js b/components/ILIAS/UI/resources/js/Table/src/datatable.class.js index 99c460228388..272fea244fc8 100755 --- a/components/ILIAS/UI/resources/js/Table/src/datatable.class.js +++ b/components/ILIAS/UI/resources/js/Table/src/datatable.class.js @@ -91,7 +91,12 @@ export default class DataTable { throw new Error('There is no
in the component\'s HTML.'); } this.#modalResponseArea = this.#component.getElementsByClassName('c-table-data__async_modal_container').item(0); - this.#responseContainer = this.#component.getElementsByClassName('c-table-data__async_message').item(0); + // Async message node may be moved to document.body (see il.UI.modal); resolve by stable id. + this.#responseContainer = document.getElementById(`${componentId}_msgmodal`) + ?? this.#component.getElementsByClassName('c-table-data__async_message').item(0); + if (this.#responseContainer === null) { + throw new Error('Could not find async message container for this table.'); + } this.#responseContent = this.#responseContainer.getElementsByClassName('c-table-data__async_messageresponse').item(0); this.#jquery = jquery; @@ -155,7 +160,10 @@ export default class DataTable { * @return {void} */ #showWarningUrlTooLong() { - const dialog = this.#component.querySelector('dialog.c-table-data__multiaction-warning'); + const dialog = document.getElementById(`${this.#component.id}_warningmodal`); + if (dialog === null) { + return; + } il.UI.modal.showModal(dialog, {}, { id: dialog.id }); } diff --git a/components/ILIAS/UI/src/templates/default/Input/tpl.tree_select.html b/components/ILIAS/UI/src/templates/default/Input/tpl.tree_select.html index f021f3b3f891..10437db25589 100644 --- a/components/ILIAS/UI/src/templates/default/Input/tpl.tree_select.html +++ b/components/ILIAS/UI/src/templates/default/Input/tpl.tree_select.html @@ -1,5 +1,5 @@
- +