From: soufiane Date: Tue, 24 Mar 2026 17:22:00 +0000 (+0100) Subject: wait #7812 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;ds=inline;p=fluidbook-toolbox.git wait #7812 --- diff --git a/resources/linkeditor/js/linkeditor.accessibility.js b/resources/linkeditor/js/linkeditor.accessibility.js new file mode 100644 index 000000000..59a01b859 --- /dev/null +++ b/resources/linkeditor/js/linkeditor.accessibility.js @@ -0,0 +1,411 @@ +import Sortable from 'sortablejs'; + +function LinkeditorAccessibility(linkeditor) { + this.linkeditor = linkeditor; + this.interactiveThreshold = 5; + this.nonInteractiveTypes = [14, 15, 39]; +} + +LinkeditorAccessibility.prototype = { + init: function () { + var $this = this; + + this.container = $("#linkeditor-panel-accessibility"); + this.maskCheckEvents = false; + + this.sortable = false; + + $(document).on('click', '#linkeditor-panel-accessibility label span.uid', function () { + navigator.clipboard.writeText($(this).attr('fb-uid')); + let tippy = $(this).data('tippyinstance'); + tippy.setContent(TRANSLATIONS.id_copied); + tippy.show(); + return false; + }); + + this.update(); + }, + + reorderSelection: function (way) { + return this.reorderLinks(this.getCurrentOrderableSelection(), way); + }, + + reorderLinks: function (links, way) { + let selectedOrder = parseInt($(links).eq(0).attr('fb-order')); + links = this.orderLinksByPosition(links, way); + let step = 1 / (links.length + 1); + $(links).each(function () { + let s = selectedOrder += step; + $(this).attr('fb-order', s); + }); + this.normalizeLinksOrder(); + }, + + reorderPageLinks: function (way) { + return this.reorderLinks(this.getOrderableLinksOnPage(), way); + }, + + reorderAllLinks: function (way) { + let $this = this; + let step = this.linkeditor.single ? 1 : 2; + for (let i = 0; i < FLUIDBOOK_DATA.settings.pages; i += step) { + let o = 0; + let links = this.orderLinksByPosition(this.getOrderableLinksOnPage(i), way); + $.each(links, function (k, v) { + LINKS[v.uid].order = o++; + if (i === $this.linkeditor.getCurrentPage()) { + $('.link[fb-uid="' + v.uid + '"]').attr('fb-order', o); + } + }); + this.linkeditor.hasChanged(); + } + this.normalizeLinksOrder(true); + }, + + moveSelectionOrder: function (way) { + let start; + let selection = this.getCurrentOrderableSelection(); + let num = selection.length; + if (num <= 0) { + return; + } + let firstSelected = $(selection).get(0); + let firstSelectedOrder = parseFloat($(firstSelected).attr('fb-order')); + let max = this.getOrderableLinksOnPage().length + 1; + + let step = 1 / (num + 1); + + switch (way) { + case'start': + start = -num; + break; + case'end': + start = max; + break; + case'up': + start = firstSelectedOrder - 1 - step; + break; + case'down': + start = firstSelectedOrder + 1 + step; + break; + } + + let selectedOrder = start; + + $(selection).each(function () { + $(this).attr('fb-order', selectedOrder); + selectedOrder += step; + }); + + this.normalizeLinksOrder(); + }, + + getOrderableLinksOnPage: function (page) { + let links; + if (page === undefined) { + links = this.linkeditor.links.getLinksOfCurrentPage(); + } else { + links = this.linkeditor.links.getLinksOfPage(page); + } + + return this.filterOrderableLinks(links); + }, + + + filterOrderableLinks: function (links) { + let $this = this; + let res = []; + $.each(links, function () { + if ($this.isInteractive(this)) { + res.push(this); + } + }); + + return this.orderLinks(res); + }, + + isInteractive: function (link) { + link = $(link); + if (link.attr('fb-calc-depth') < this.interactiveThreshold * 10) { + return false; + } + if (this.nonInteractiveTypes.indexOf(parseInt(link.attr('fb-type'))) > -1) { + return false; + } + let x = parseFloat(link.attr('fb-left')); + let y = parseFloat(link.attr('fb-top')); + let w = parseFloat(link.attr('fb-width')); + let h = parseFloat(link.attr('fb-height')); + if (x > this.linkeditor.fw || y > this.linkeditor.fh) { + return false; + } + if (x + w < 0 || y + h < 0) { + return false; + } + return true; + + }, + + orderLinks: function (links) { + let arr = links; + if (links instanceof jQuery) { + arr = $(links).toArray(); + } + return arr.sort(function (a, b) { + return parseFloat($(a).attr('fb-order')) - parseFloat($(b).attr('fb-order')); + }); + }, + + orderLinksByPosition: function (links, way) { + let $this = this; + let doublePage = !this.linkeditor.single && !this.linkeditor.utils.isSpecialPage(this.linkeditor.currentPage); + let pw = this.linkeditor.pw; + + return $(links).toArray().sort(function (a, b) { + let ca = $this.getLinkDimensions(a); + let cb = $this.getLinkDimensions(b); + + let pa = ca.page; + let pb = cb.page; + let xa = ca.x; + let xb = cb.x; + if (doublePage) { + if (xa >= pw) { + xa -= pw; + pa++; + } + if (xb >= pw) { + xb -= pw; + pb++; + } + if (pa !== pb) { + return pa - pb; + } + } + + + let wa = ca.width; + let wb = cb.width; + + let xTolerance = Math.min(wa, wb) / 2; + + let ha = ca.height; + let hb = cb.height; + + let yTolerance = Math.min(ha, hb) / 2; + + xa += wa / 2; + xb += wb / 2; + + let ya = ca.y + ha / 2; + let yb = cb.y + hb / 2; + + let xdiff = xa - xb; + let ydiff = ya - yb; + + if (way === 'columns') { + return Math.abs(xdiff) > xTolerance ? xdiff : ydiff; + } else if (way === 'lines') { + return Math.abs(ydiff) > yTolerance ? ydiff : xdiff; + } + }); + }, + + getLinkDimensions: function (link) { + if (link.left !== undefined) { + return { + x: parseFloat(link.left), + y: parseFloat(link.top), + width: parseFloat(link.width), + height: parseFloat(link.height), + page: parseInt(link.page), + } + } else { + return { + x: parseFloat($(link).attr('fb-left')), + y: parseFloat($(link).attr('fb-top')), + width: parseFloat($(link).attr('fb-width')), + height: parseFloat($(link).attr('fb-height')), + page: $(link).attr('fb-page'), + }; + } + }, + + getCurrentOrderableSelection: function () { + return this.filterOrderableLinks(this.linkeditor.links.getCurrentSelection()); + }, + + normalizeLinksOrder: function (refresh) { + if (refresh === undefined) { + refresh = true; + } + let $this = this; + let links = []; + $('#linkeditor-links .link:not(.pendingCreate)').each(function () { + links.push({ + link: $(this), + interactive: $this.isInteractive($(this)), + order: parseFloat($(this).attr('fb-order'),) + }); + }); + + links.sort(function (a, b) { + if (a.interactive === b.interactive) { + return a.order - b.order + } + return b.interactive - a.interactive; + }); + + let i = 0; + let wrapper = $("#linkeditor-links"); + $(links).each(function (k, v) { + $(v.link).attr('fb-order', i++); + $(v.link).attr('fb-orderable', v.interactive ? '1' : '0'); + $(wrapper).append($(v.link)); + }); + + if (refresh) { + this.linkeditor.links.updateLinksData(links, ['order']); + this.linkeditor.hasChanged(); + } + this.linkeditor.links.pageMaxOrderIndex = i; + }, + + getLinkLevel: function (link) { + let d = parseInt($(link).attr('fb-calc-depth')); + var m = 1; + if (d >= 30 && d < this.interactiveThreshold * 10) { + m = 10; + } + return Math.floor((m * d) / 10) / m; + }, + + update: function () { + if (this.container === undefined) { + return; + } + if (!this.container.hasClass('open')) { + return; + } + var $this = this; + this.container.addClass('toolbar-top').addClass('toolbar-bottom'); + this.container.html(this.getTopToolbar() + '
'); + let wrapper = this.container.find('.linkeditor-panel-wrapper'); + var accessibility = []; + this.normalizeLinksOrder(false); + $(this.orderLinks(this.linkeditor.links.getLinksOfCurrentPage())).each(function () { + let type = $(this).attr('fb-type'); + let dest = $(this).attr('fb-to'); + let uid = $(this).attr('fb-uid'); + let interactive = $this.isInteractive($(this)); + + if (dest === '') { + dest = '' + TRANSLATIONS.empty + ''; + } + var l = '
'; + l += ' '; + l += ''; + l += '
'; + + accessibility.push({ + interactive: interactive, + zindex: parseInt($(this).attr('fb-calc-zindex')), + html: l, + order: parseInt($(this).attr('fb-order')), + }); + }); + + accessibility.sort(function (a, b) { + if (a.interactive === b.interactive) { + return a.order - b.order + } + return b.interactive - a.interactive; + }); + + var seenLevels = {}; + $.each(accessibility, function (k, v) { + let wrapperClass = 'order' + (v.interactive ? '-interactive' : '-noninteractive') + '-wrapper'; + if (seenLevels[v.interactive] === undefined) { + seenLevels[v.interactive] = true; + wrapper.append('

' + (v.interactive ? TRANSLATIONS.interactive_links : TRANSLATIONS.noninteractive_links) + '

'); + } + $this.container.find('.' + wrapperClass).append(v.html); + }); + this.container.append(this.getBottomToolbar()); + + let sortableWrapper = $('.order-interactive-wrapper').get(0); + try { + this.sortable.destroy(); + } catch (e) { + + } + if ($('.order-interactive-wrapper').length > 0) { + this.sortable = Sortable.create(sortableWrapper, { + handle: '.drag', onSort: function (e) { + let i = 0; + $(sortableWrapper).find('div.layer').each(function () { + let uid = $(this).find('label.layer').data('uid'); + let link = $('#linkeditor-links .link[fb-uid="' + uid + '"]'); + $(link).attr('fb-order', i++); + }); + $this.normalizeLinksOrder(); + }, + }); + } + + this.updateSelection(); + this.linkeditor.initTooltips(); + this.linkeditor.initIcons(); + }, + + getTopToolbar: function () { + let res = '
'; + return res; + }, + + getBottomToolbar: function () { + let res = '
'; + return res; + }, + + updateSelection() { + this.linkeditor.panels.updatePanelSelection(this); + let l = this.getCurrentOrderableSelection().length; + if (l < 1) { + $('[data-action="accessibility.moveSelectionOrder"]').addClass('disabled'); + } else { + $('[data-action="accessibility.moveSelectionOrder"]').removeClass('disabled'); + } + if (l < 2) { + $('[data-action="accessibility.reorderSelection"]').addClass('disabled'); + } else { + $('[data-action="accessibility.reorderSelection"]').removeClass('disabled'); + } + }, + + resize: function () { + + }, +} + +export default LinkeditorAccessibility;