PageSourceSearch

https://ops.iris.edu.gr/_content/Argus.Web.Shared/js/shared.js?v=XJOc7MueEcRrPg5JmoQcf-peLlD3Stl7ELqDBAjy8fM

js iris.edu.gr collected 2026-10-08 10:19:24 UTC 10,314 bytes, 259 lines download raw bytes

1window.scrollToBottom = (elementOrId) => {
2    if (!elementOrId) return;
3    const el = (typeof elementOrId === 'string')
4        ? document.getElementById(elementOrId)
5        : elementOrId;
6    if (el && el.scrollTop !== undefined) {
7        el.scrollTop = el.scrollHeight;
8    }
9};
10
11// Saves the current scroll height of the element so we can restore relative position after prepending content.
12window.argusGetScrollHeight = (el) => el ? el.scrollHeight : 0;
13
14// Adjusts scrollTop so the viewport stays on the same content after new items were prepended above.
15window.argusRestoreScrollAfterPrepend = (el, scrollHeightBefore) => {
16    if (!el) return;
17    el.scrollTop = el.scrollHeight - scrollHeightBefore;
18};
19
20// Auto-expands a textarea from 1 row up to ~4 rows, then scrolls internally.
21window.argusAutoExpandTextarea = (el) => {
22    if (!el) return;
23    el.style.height = 'auto';
24    const lineHeight = parseInt(getComputedStyle(el).lineHeight) || 20;
25    const maxHeight = lineHeight * 4 + parseInt(getComputedStyle(el).paddingTop) * 2;
26    el.style.overflowY = el.scrollHeight > maxHeight ? 'auto' : 'hidden';
27    el.style.height = Math.min(el.scrollHeight, maxHeight) + 'px';
28};
29
30// Resets textarea back to single-row height after message is sent.
31window.argusResetTextarea = (el) => {
32    if (!el) return;
33    el.value = '';           // clear DOM value immediately (Blazor will sync on next render)
34    el.style.height = 'auto';
35    el.style.overflowY = 'hidden';
36};
37
38// Attaches a native keydown listener to the chat textarea so Enter can be
39// intercepted with preventDefault() before the browser inserts a newline.
40// dotNetRef must expose [JSInvokable] OnEnterPressed().
41window.argusInitChatTextarea = (el, dotNetRef) => {
42    if (!el || !dotNetRef) return;
43    el._chatKeyHandler = (e) => {
44        if (e.key === 'Enter' && !e.shiftKey) {
45            e.preventDefault();
46            dotNetRef.invokeMethodAsync('OnEnterPressed');
47        }
48    };
49    el.addEventListener('keydown', el._chatKeyHandler);
50};
51
52// Pins the chat page to fill from below the last header bar to the bottom of the viewport.
53// Uses position:fixed on the chat wrapper, and a sentinel div to measure where content starts.
54window.argusChatFillHeight = (sentinel, chatPage) => {
55    const apply = () => {
56        if (!sentinel) return;
57        const top = sentinel.getBoundingClientRect().top;
58        document.documentElement.style.setProperty('--argus-chat-top', Math.round(top) + 'px');
59    };
60    requestAnimationFrame(() => {
61        apply();
62        // Second pass after a short delay handles any deferred Blazor/theme renders
63        setTimeout(apply, 300);
64    });
65    window.addEventListener('resize', apply, { passive: true });
66};
67
68window.AgTextBox = (function () {
69    'use strict';
70
71    // Map of elementId -> { element: HTMLInputElement, handler: Function }
72    const handlers = new Map();
73
74    // Returns 0=neutral, 1=Greek, 2=Latin for a single character
75    function getAlphabetMode(ch) {
76        const code = ch.codePointAt(0);
77        if (code === undefined) return 0;
78
79        // Greek Extended: U+0370-U+03FF (Greek and Coptic), U+1F00-U+1FFF (Greek Extended)
80        if ((code >= 0x0370 && code <= 0x03FF) || (code >= 0x1F00 && code <= 0x1FFF))
81            return 1;
82
83        // Latin: Basic Latin A-Z/a-z + Latin-1 Supplement + Latin Extended A/B + IPA Extensions + Latin Extended Additional
84        if ((code >= 0x0041 && code <= 0x005A) ||
85            (code >= 0x0061 && code <= 0x007A) ||
86            (code >= 0x00C0 && code <= 0x00FF) ||
87            (code >= 0x0100 && code <= 0x017F) ||
88            (code >= 0x0180 && code <= 0x024F) ||
89            (code >= 0x1E00 && code <= 0x1EFF))
90            return 2;
91
92        return 0; // digits, punctuation, spaces, other scripts → neutral
93    }
94
95    // Mirrors C# RemoveMixedGreekLatin. Also tracks cursor position through the transformation.
96    function removeMixedGreekLatin(input, cursorPos) {
97        if (!input) return { value: input, cursor: cursorPos };
98
99        let selectedAlphabet = 0;
100        let result = '';
101        let newCursor = 0;
102
103        for (let i = 0; i < input.length; i++) {
104            const ch = input[i];
105            const mode = getAlphabetMode(ch);
106
107            let include;
108            if (mode === 0) {
109                include = true;
109                    // neutral chars (digits, spaces, etc.) always pass
110            } else if (selectedAlphabet === 0) {
111                selectedAlphabet = mode;           // lock alphabet on first letter
112                include = true;
113            } else {
114                include = mode === selectedAlphabet; // drop letters from the other alphabet
115            }
116
117            if (include) {
118                result += ch;
119                if (i < cursorPos) newCursor++;    // keep cursor aligned with surviving chars
120            }
121            // if excluded: newCursor doesn't advance → cursor stays in place
122        }
123
124        return { value: result, cursor: Math.min(newCursor, result.length) };
125    }
126
127    // Mirrors C# Conv.ToUpperGreekSafe: uppercase + strip diacritics (NFD → remove Mn marks → NFC)
128    function toUpperGreekSafe(input) {
129        if (!input) return input;
130        return input
131            .toUpperCase()
132            .normalize('NFD')
133            .replace(/\p{Mn}/gu, '')  // strip all combining / nonspacing marks (accents, tonos, etc.)
134            .normalize('NFC');
135    }
136
137    // Patch the instance's value property so that any programmatic write 
138    // (Telerik/Blazor re-render) restores the cursor when the field is focused.
139    // We override on the instance only, prototype is untouched.
140    function patchInputCursor(input) {
141        if (input._agCursorPatched) return;
142
143        const proto = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
144
145        Object.defineProperty(input, 'value', {
146            get: proto.get,
147            set: function (v) {
148
149                if (v == null) v = '';
150
151                const focused = document.activeElement === this;
152                const start   = focused ? this.selectionStart : -1;
153                const end     = focused ? this.selectionEnd   : -1;
154                proto.set.call(this, v);
155                if (focused && start >= 0) {
156                    this.setSelectionRange(
157                        Math.min(start, v.length),
158                        Math.min(end,   v.length)
159                    );
160                }
161            },
162            configurable: true
163        });
164
165        input._agCursorPatched = true;
166    }
167
168    function unpatchInputCursor(input) {
169        if (!input._agCursorPatched) return;
170        delete input.value;           // removes own property → prototype takes over again
171        delete input._agCursorPatched;
172    }
173
174    function createHandler(multiLanguageOff, capitalize) {
175        let processing = false; // re-entrancy guard for the synthetic event we dispatch
176
177        return function (e) {
178            if (processing) return;
179
180            const el = e.target;
181            const cursorPos = el.selectionStart;
182            let value = el.value;
183            let newCursor = cursorPos;
184
185            if (multiLanguageOff) {
186                const r = removeMixedGreekLatin(value, cursorPos);
187                value = r.value;
188                newCursor = r.cursor;
189            }
190
191            if (capitalize) {
192                // toUpperGreekSafe is effectively length-preserving for NFC Greek/Latin input
193                // (each accented NFC char → one unaccented NFC char), so cursor stays valid
194                value = toUpperGreekSafe(value);
195            }
196
197            if (value !== el.value) {
198                processing = true;
199                el.value = value;
200                el.setSelectionRange(newCursor, newCursor);
201                // Dispatch a new input event so Telerik/Blazor picks up the corrected value
202                el.dispatchEvent(new InputEvent('input', { bubbles: true, cancelable: false }));
203                processing = false;
204            }
205        };
206    }
207
208    return {
209        /**
210         * Attach a client-side input handler to the element with the given id.
211         * @param {string}  id               - The id attribute of the <input> element (matches TelerikTextBox Id param)
212         * @param {boolean} multiLanguageOff - true when MultiLanguage=false (restrict to first-seen alphabet)
213         * @param {boolean} capitalize       - true when Capitalize=true (uppercase + strip accents)
214         */
215        init: function (id, multiLanguageOff, capitalize) {
216            this.dispose(id); // clean up any previous handler for this id
217
218            const el = document.getElementById(id);
219            if (!el) return;
220
221            // Telerik renders the <input> directly with the given id, but guard against wrappers
222            const input = el.tagName === 'INPUT' ? el : el.querySelector('input');
223            if (!input) return;
224
225            // Always patch, prevents Blazor/Telerik re-renders from mov
225ing the cursor,
226            // even when no text transformation is configured (e.g. inside EditForms).
227            patchInputCursor(input);
228
229            let handler = null;
230            if (multiLanguageOff || capitalize) {
231                handler = createHandler(multiLanguageOff, capitalize);
232                input.addEventListener('input', handler);
233            }
234
235            handlers.set(id, { element: input, handler: handler });
236        },
237
238        dispose: function (id) {
239            const entry = handlers.get(id);
240            if (entry) {
241                if (entry.handler)
242                    entry.element.removeEventListener('input', entry.handler);
243                unpatchInputCursor(entry.element);
244                handlers.delete(id);
245            }
246        }
247    };
248})();
249
250window.argusDownloadFile = (url, fileName) => {
251    const a = document.createElement('a');
252    a.href = url;
253    a.download = fileName || '';
254    a.style.display = 'none';
255    document.body.appendChild(a);
256    a.click();
257    document.body.removeChild(a);
258};
259

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.