PageSourceSearch

https://ecampus.ufam.edu.br/ecampus/js//vlibras-drag.js

js ufam.edu.br collected 2026-09-24 08:54:22 UTC 5,334 bytes, 141 lines download raw bytes

1(function () {
2    var STORAGE_KEY = 'vlibrasPosition';
3    var MOVED_EPSILON = 2;
4    var DRAGGING_CLASS = 'vlibras-dragging';
5
6    function getWidget() {
7        return document.querySelector('div[vw].enabled');
8    }
9
10    function clamp(value, min, max) {
11        return Math.min(Math.max(value, min), max);
12    }
13
14    function applyPosition(el, right, bottom) {
15        var rect = el.getBoundingClientRect();
16        var maxRight = Math.max(window.innerWidth - rect.width, 0);
17        var maxBottom = Math.max(window.innerHeight - rect.height, 0);
18        right = clamp(right, 0, maxRight);
19        bottom = clamp(bottom, 0, maxBottom);
20        el.style.setProperty('left', 'auto', 'important');
21        el.style.setProperty('top', 'auto', 'important');
22        el.style.setProperty('right', right + 'px', 'important');
23        el.style.setProperty('bottom', bottom + 'px', 'important');
24        el.style.setProperty('transform', 'none', 'important');
25        return { right: right, bottom: bottom };
26    }
27
28    function loadSavedPosition(el) {
29        var saved;
30        try {
31            saved = JSON.parse(localStorage.getItem(STORAGE_KEY));
32        } catch (e) {
33            return;
34        }
35        if (saved && typeof saved.right === 'number' && typeof saved.bottom === 'number') {
36            applyPosition(el, saved.right, saved.bottom);
37        }
38    }
39
40    function savePosition(right, bottom) {
41        try {
42            localStorage.setItem(STORAGE_KEY, JSON.stringify({ right: right, bottom: bottom }));
43        } catch (e) {
44            // localStorage indisponivel (modo privado, quota etc): ignora.
45        }
46    }
47
48    function setupDrag(widget, handle) {
49        var dragging = false;
50        var moved = false;
51        var startX, startY, startRight, startBottom;
52
53        handle.style.touchAction = 'none';
54
55        handle.addEventListener('pointerdown', function (ev) {
56            if (ev.button !== undefined && ev.button !== 0) return;
57            dragging = true;
58            moved = false;
59            startX = ev.clientX;
60            startY = ev.clientY;
61            var style = window.getComputedStyle(widget);
62            startRight = parseFloat(style.right) || 0;
63            startBottom = parseFloat(style.bottom) || 0;
64            // Evita o drag nativo de imagem do navegador e a selecao de texto,
65            // que atrapalham o arraste customizado logo no primeiro movimento.
66            ev.preventDefault();
67            // Feedback visual imediato: ao segurar o botao, ele ja mostra que
68            // esta liberado para ser arrastado, antes mesmo de mover o mouse.
69            handle.classList.add(DRAGGING_CLASS);
70            if (handle.setPointerCapture) {
71                handle.setPointerCapture(ev.pointerId);
72            }
73        });
74
75        handle.addEventListener('pointermove', function (ev) {
76            if (!dragging) return;
77            var dx = ev.clientX - startX;
78            var dy = ev.clientY - startY;
79            if (!moved && (Math.abs(dx) > MOVED_EPSILON || Math.abs(dy) > MOVED_EPSILON)) {
80                moved = true;
81            }
82            // Acompanha o cursor desde o primeiro pixel de movimento, sem
83            // esperar um limite minimo, para o arraste parecer imediato.
84            applyPosition(widget, startRight - dx, startBottom - dy);
85        });
86
87        function endDrag() {
88            if (!dragging) return;
89            dragging = false;
90            handle.classList.remove(DRAGGING_CLASS);
91            if (moved) {
92                var style = window.getComputedStyle(widget);
93                savePosition(parseFloat(style.right) || 0, parseFloat(style.bottom) || 0);
94                // O clique gerado pelo navegador logo apos o "pointerup" chega
95                // de forma sincrona e ainda vera moved=true para ser
96                // suprimido; este timeout so limpa a flag caso, por algum
97                // motivo, esse clique nao chegue a ocorrer.
98                setTimeout(function () { moved = false; }, 0);
99            }
100        }
101
102        handle.addEventListener('pointerup', endDrag);
103        handle.addEventListener('pointercancel', endDrag);
104
105        // Se o gesto foi um arraste, bloqueia o clique que o VLibras usa
106        // para abrir/fechar o painel de traducao.
107        handle.addEventListener('click', function (ev) {
108            if (moved) {
109                ev.stopImmediatePropagation();
110                ev.preventDefault();
111                moved = false;
112            }
113        }, true);
114    }
115
116    function init() {
117        var widget = getWidget();
118        if (!widget) return;
119        var handle = widget.querySelector('[vw-access-button]');
120        if (!handle) return;
121
122        loadSavedPosition(widget);
123        setupDrag(widget, handle);
124    }
125
126    if (document.readyState === 'loading') {
127        document.addEventListener('DOMContentLoaded', init);
128    } else {
129        init();
130    }
131
132    // O proprio script do VLibras reaplica sua posicao padrao (centralizada)
133    // via estilo inline quando a pagina termina de carregar. Reaplicamos a
134    // posicao salva do usuario logo em seguida para que ela prevaleca.
135    window.addEventListener('load', function () {
136        setTimeout(function () {
137            var widget = getWidget();
138            if (widget) loadSavedPosition(widget);
139        }, 50);
140    });
141})();

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.