PageSourceSearch

https://cyou.org/js/scripts.js

js cyou.org collected 2026-09-30 05:05:29 UTC 8,025 bytes, 209 lines download raw bytes

1
2function getUserDeviceInfo() {
3    var parser = new UAParser();
4    var result = parser.getResult();
5    return {
6        operatingSystem: result.os.name,
7        operatingSystemVersion: result.os.version,
8        browserInfo: result.browser.name + ' ' + result.browser.version
9    };
10}
11
12function updateLanguage(lang) {
13    document.querySelector('html').setAttribute('lang', lang.cultureCode);
14}
15
16function scrollToBottom(selector) {
17    let element = document.querySelector(`.${selector}`);
18    if (element) {
19        element.scrollTop = element.scrollHeight;
20    }
21}
22    
23function scrollToTop(selector) {
24    let element = document.querySelector(`.${selector}`);
25    if(element) {
26        element.scrollTop = 0;
27    }
28}
29
30function temporarilyDisableAutoHideForContextMenu(contextMenuId) {
31    const element = document.getElementById(contextMenuId);
32    if (element) {
33        element.dataset.autohide = 'false';
34        setTimeout(function () {
35            element.dataset.autohide = 'true';
36        }, 300);
37    }
38}
39
40function clickById(id){
41    document.getElementById(id).click();
42}
43
44function clearFileSelector(){
45    document.querySelector(".mud-file-upload input[type='file']").value= null;
46}
47
48function trackPageView(url) {
49    gtag('event', 'page_view', { page_path: url });
50}
51
52function attachInputValidation(wrapper, allowedPattern, maxLength) {
53    // Store pattern/maxLength on wrapper so they can be updated dynamically
54    // (e.g. when backend selection changes the allowed character set).
55    wrapper.dataset.allowedPattern = allowedPattern;
56    wrapper.dataset.maxLength = String(maxLength);
57
58    function sanitize(field) {
59        const pattern = new RegExp(`[^${wrapper.dataset.allowedPattern}]`, 'g');
60        const ml = parseInt(wrapper.dataset.maxLength) || 0;
61        let sanitized = field.value.replace(pattern, '');
62        if (ml > 0) sanitized = sanitized.slice(0, ml);
63        if (sanitized !== field.value) {
64            field.value = sanitized;
65            field.dispatchEvent(new Event('input', { bubbles: true }));
66        }
67    }
68
69    function attachToInput(field) {
70        if (field.dataset.validationAttached) return;
71        field.dataset.validationAttached = 'true';
72        field.addEventListener('input', (event) => {
73            if (!event.isTrusted) return; // Ignore our own synthetic events
74            sanitize(field);
75        });
76    }
77
78    const existing = wrapper.querySelector('input');
79    if (existing) attachToInput(existing);
80
81    // Guard: only create one MutationObserver per wrapper.
82    if (wrapper.dataset.observerAttached) return;
83    wrapper.dataset.observerAttached = 'true';
84
85    // Re-attach when @key causes MudTextField to be recreated inside the wrapper.
86    new MutationObserver(() => {
87        const input = wrapper.querySelector('input');
88        if (input) attachToInput(input);
89    }).observe(wrapper, { childList: true, subtree: true });
90}
91
92function attachPasteHandler(elementId, dotNetHelper) {
93    const field = document.getElementById(elementId);
94    if (field) {
95        field.addEventListener('paste', async (event) => {
96            event.preventDefault();
97            const clipboardData = event.clipboardData || window.clipboardData;
98            const pastedData = clipboardData.getData('Text');
99
100            // Invoke the C# method and pass the pasted data
101            await dotNetHelper.invokeMethodAsync('OnPasteReceived', pastedData, field.id);
102        });
103    }
104}
105
106function getElementPosition (element) {
107    if (!element) {
108        return null;
109    }
110    const rect = element.getBoundingClientRect();
111    return {
112            top: rect.top,
113            left: rect.left,
114            right: rect.right,
115            bottom: rect.bottom,
116            width: rect.width,
117            height: rect.height,
118            windowScrollX: window.scrollX,
119            windowScrollY: window.scrollY
120    };
121}
122
123function getElementPositionWithinScrollableParent (element, parent) {
124    if (!element || !parent) return null;
125
126    const elementRect = element.getBoundingClientRect();
127    const parentRect = parent.getBoundingClientRect();
128
129    return {
130        top: elementRect.top - parentRect.top + parent.scrollTop,
131        left: elementRect.left - parentRect.left + parent.scrollLeft,
132        width: elementRect.width,
133        height: elementRect.height
134    };
135}
136
137function adjustContextMenuPositionInScrollableContainer(contextMenuId, sourceDiv, containerElement) {
138    const menuElement = document.getElementById(contextMenuId);
139    if (!menuElement || !containerElement || !sourceDiv) {
140        console.warn("Menu, container, or source element not found.");
141        return;
142    }
143
144    const containerRect = containerElement.getBoundingClientRect();
145    const menuRect = menuElement.getBoundingClientRect();
146    const sourceWithin = getElementPositionWithinScrollableParent(sourceDiv, containerElement); // {top,left,width,height}
147    if (!sourceWithin) return;
148
149    // Current menu position converted to container scroll space
150    const menuLeftInContainer = menuRect.left - containerRect.left + containerElement.scrollLeft;
151    const menuTopInContainer = menuRect.top - containerRect.top + containerElement.scrollTop;
152
153    let newLeft = menuLeftInContainer;
154    let newTop = menuTopInContainer;
155
156    // --- Horizontal: flip left if the menu overflows the container's right edge (viewport comparison is OK) ---
157    if (menuRect.right > containerRect.right) {
158        // Place the menu to the left of the trigger, in container space
159        newLeft = sourceWithin.left - menuRect.width;
160    }
161
162    // Clamp horizontally to the visible area of the container
163    const minLeft = containerElement.scrollLeft;
164    const maxLeft = containerElement.scrollLeft + containerElement.clientWidth - menuRect.width;
165    newLeft = Math.min(Math.max(newLeft, minLeft), Math.max(minLeft, maxLeft));
166
167    // --- Vertical: align the menu just above the trigger in container space to avoid "creeping" ---
168    const desiredTop = sourceWithin.top - menuRect.height;
169
170    // If it's drifted above the desired anchor OR above the visible top, snap back
171    if (menuTopInContainer < desiredTop || menuRect.top < containerRect.top) {
172        newTop = desiredTop;
173    }
174
175    // Clamp vertically to the visible area of the container
176    const minTop = containerElement.scrollTop;
177    const maxTop = containerElement.scrollTop + containerElement.clientHeight - menuRect.height;
178    newTop = Math.min(Math.max(newTop, minTop), Math.max(minTop, maxTop));
179
180    // Apply numbers in the same coordinate system the menu was initially shown with (container scroll space)
181    menuElement.style.left = `${Math.round(newLeft)}px`;
182    menuElement.style.top = `${Math.round(newTop)}px`;
183}
184
185function adjustContextMenuPositionOnPage(contextMenuId, sourceDiv) {
186    const menuElement = document.getElementById(contextMenuId);
187    if (!menuElement) {
188        console.warn("Menu element not found.");
189        return;
190    }
191    const menuRect = menuElement.getBoundingClientRect();
192    const sourceDivRect = sourceDiv.getBoundingClientRect();
193
194    let adjustedY = menuRect.top;
195    var elementPosition = getElementPosition(sourceDiv);
196
197    // The component does not take into account the scrolling of the page/container, 
198    // therefore on multiple openings of the contextmenu it will jump further up until it reaches the point where it fits into the unscrolled page area
199    if (parseInt(menuElement.style.top, 10) < sourceDivRect.top+elementPosition.windowScrollY-menuRect.height) {
200        adjustedY = sourceDivRect.top + elementPosition.windowScrollY - menuRect.height;
201        menuElement.style.top = `${adjustedY}px`;
202    }
203
204}
205
206function createPdfUrl(bytes) {
207        const blob = new Blob([new Uint8Array(bytes)], { type: "application/pdf" });
208        return URL.createObjectURL(blob);
209}

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.